[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 package bigrat; 2 require "bigint.pl"; 3 # 4 # This library is no longer being maintained, and is included for backward 5 # compatibility with Perl 4 programs which may require it. 6 # 7 # In particular, this should not be used as an example of modern Perl 8 # programming techniques. 9 # 10 # Arbitrary size rational math package 11 # 12 # by Mark Biggar 13 # 14 # Input values to these routines consist of strings of the form 15 # m|^\s*[+-]?[\d\s]+(/[\d\s]+)?$|. 16 # Examples: 17 # "+0/1" canonical zero value 18 # "3" canonical value "+3/1" 19 # " -123/123 123" canonical value "-1/1001" 20 # "123 456/7890" canonical value "+20576/1315" 21 # Output values always include a sign and no leading zeros or 22 # white space. 23 # This package makes use of the bigint package. 24 # The string 'NaN' is used to represent the result when input arguments 25 # that are not numbers, as well as the result of dividing by zero and 26 # the sqrt of a negative number. 27 # Extreamly naive algorthims are used. 28 # 29 # Routines provided are: 30 # 31 # rneg(RAT) return RAT negation 32 # rabs(RAT) return RAT absolute value 33 # rcmp(RAT,RAT) return CODE compare numbers (undef,<0,=0,>0) 34 # radd(RAT,RAT) return RAT addition 35 # rsub(RAT,RAT) return RAT subtraction 36 # rmul(RAT,RAT) return RAT multiplication 37 # rdiv(RAT,RAT) return RAT division 38 # rmod(RAT) return (RAT,RAT) integer and fractional parts 39 # rnorm(RAT) return RAT normalization 40 # rsqrt(RAT, cycles) return RAT square root 41 42 # Convert a number to the canonical string form m|^[+-]\d+/\d+|. 43 sub main'rnorm { #(string) return rat_num 44 local($_) = @_; 45 s/\s+//g; 46 if (m#^([+-]?\d+)(/(\d*[1-9]0*))?$#) { 47 &norm($1, $3 ? $3 : '+1'); 48 } else { 49 'NaN'; 50 } 51 } 52 53 # Normalize by reducing to lowest terms 54 sub norm { #(bint, bint) return rat_num 55 local($num,$dom) = @_; 56 if ($num eq 'NaN') { 57 'NaN'; 58 } elsif ($dom eq 'NaN') { 59 'NaN'; 60 } elsif ($dom =~ /^[+-]?0+$/) { 61 'NaN'; 62 } else { 63 local($gcd) = &'bgcd($num,$dom); 64 $gcd =~ s/^-/+/; 65 if ($gcd ne '+1') { 66 $num = &'bdiv($num,$gcd); 67 $dom = &'bdiv($dom,$gcd); 68 } else { 69 $num = &'bnorm($num); 70 $dom = &'bnorm($dom); 71 } 72 substr($dom,$[,1) = ''; 73 "$num/$dom"; 74 } 75 } 76 77 # negation 78 sub main'rneg { #(rat_num) return rat_num 79 local($_) = &'rnorm(@_); 80 tr/-+/+-/ if ($_ ne '+0/1'); 81 $_; 82 } 83 84 # absolute value 85 sub main'rabs { #(rat_num) return $rat_num 86 local($_) = &'rnorm(@_); 87 substr($_,$[,1) = '+' unless $_ eq 'NaN'; 88 $_; 89 } 90 91 # multipication 92 sub main'rmul { #(rat_num, rat_num) return rat_num 93 local($xn,$xd) = split('/',&'rnorm($_[$[])); 94 local($yn,$yd) = split('/',&'rnorm($_[$[+1])); 95 &norm(&'bmul($xn,$yn),&'bmul($xd,$yd)); 96 } 97 98 # division 99 sub main'rdiv { #(rat_num, rat_num) return rat_num 100 local($xn,$xd) = split('/',&'rnorm($_[$[])); 101 local($yn,$yd) = split('/',&'rnorm($_[$[+1])); 102 &norm(&'bmul($xn,$yd),&'bmul($xd,$yn)); 103 } 104 105 # addition 106 sub main'radd { #(rat_num, rat_num) return rat_num 107 local($xn,$xd) = split('/',&'rnorm($_[$[])); 108 local($yn,$yd) = split('/',&'rnorm($_[$[+1])); 109 &norm(&'badd(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd)); 110 } 111 112 # subtraction 113 sub main'rsub { #(rat_num, rat_num) return rat_num 114 local($xn,$xd) = split('/',&'rnorm($_[$[])); 115 local($yn,$yd) = split('/',&'rnorm($_[$[+1])); 116 &norm(&'bsub(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd)); 117 } 118 119 # comparison 120 sub main'rcmp { #(rat_num, rat_num) return cond_code 121 local($xn,$xd) = split('/',&'rnorm($_[$[])); 122 local($yn,$yd) = split('/',&'rnorm($_[$[+1])); 123 &bigint'cmp(&'bmul($xn,$yd),&'bmul($yn,$xd)); 124 } 125 126 # int and frac parts 127 sub main'rmod { #(rat_num) return (rat_num,rat_num) 128 local($xn,$xd) = split('/',&'rnorm(@_)); 129 local($i,$f) = &'bdiv($xn,$xd); 130 if (wantarray) { 131 ("$i/1", "$f/$xd"); 132 } else { 133 "$i/1"; 134 } 135 } 136 137 # square root by Newtons method. 138 # cycles specifies the number of iterations default: 5 139 sub main'rsqrt { #(fnum_str[, cycles]) return fnum_str 140 local($x, $scale) = (&'rnorm($_[$[]), $_[$[+1]); 141 if ($x eq 'NaN') { 142 'NaN'; 143 } elsif ($x =~ /^-/) { 144 'NaN'; 145 } else { 146 local($gscale, $guess) = (0, '+1/1'); 147 $scale = 5 if (!$scale); 148 while ($gscale++ < $scale) { 149 $guess = &'rmul(&'radd($guess,&'rdiv($x,$guess)),"+1/2"); 150 } 151 "$guess"; # quotes necessary due to perl bug 152 } 153 } 154 155 1;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 17 22:47:18 2015 | Cross-referenced by PHPXref 0.7.1 |