4 # This library is no longer being maintained, and is included for backward
5 # compatibility with Perl 4 programs which may require it.
6 # This legacy library is deprecated and will be removed in a future
9 # In particular, this should not be used as an example of modern Perl
10 # programming techniques.
12 # Arbitrary size rational math package
16 # Input values to these routines consist of strings of the form
17 # m|^\s*[+-]?[\d\s]+(/[\d\s]+)?$|.
19 # "+0/1" canonical zero value
20 # "3" canonical value "+3/1"
21 # " -123/123 123" canonical value "-1/1001"
22 # "123 456/7890" canonical value "+20576/1315"
23 # Output values always include a sign and no leading zeros or
25 # This package makes use of the bigint package.
26 # The string 'NaN' is used to represent the result when input arguments
27 # that are not numbers, as well as the result of dividing by zero and
28 # the sqrt of a negative number.
29 # Extreamly naive algorthims are used.
31 # Routines provided are:
33 # rneg(RAT) return RAT negation
34 # rabs(RAT) return RAT absolute value
35 # rcmp(RAT,RAT) return CODE compare numbers (undef,<0,=0,>0)
36 # radd(RAT,RAT) return RAT addition
37 # rsub(RAT,RAT) return RAT subtraction
38 # rmul(RAT,RAT) return RAT multiplication
39 # rdiv(RAT,RAT) return RAT division
40 # rmod(RAT) return (RAT,RAT) integer and fractional parts
41 # rnorm(RAT) return RAT normalization
42 # rsqrt(RAT, cycles) return RAT square root
44 # Convert a number to the canonical string form m|^[+-]\d+/\d+|.
45 sub main'rnorm { #(string) return rat_num
48 if (m#^([+-]?\d+)(/(\d*[1-9]0*))?$#) {
49 &norm($1, $3 ? $3 : '+1');
55 # Normalize by reducing to lowest terms
56 sub norm { #(bint, bint) return rat_num
57 local($num,$dom) = @_;
60 } elsif ($dom eq 'NaN') {
62 } elsif ($dom =~ /^[+-]?0+$/) {
65 local($gcd) = &'bgcd($num,$dom);
68 $num = &'bdiv($num,$gcd);
69 $dom = &'bdiv($dom,$gcd);
74 substr($dom,0,1) = '';
80 sub main'rneg { #(rat_num) return rat_num
81 local($_) = &'rnorm(@_);
82 tr/-+/+-/ if ($_ ne '+0/1');
87 sub main'rabs { #(rat_num) return $rat_num
88 local($_) = &'rnorm(@_);
89 substr($_,0,1) = '+' unless $_ eq 'NaN';
94 sub main'rmul { #(rat_num, rat_num) return rat_num
95 local($xn,$xd) = split('/',&'rnorm($_[0]));
96 local($yn,$yd) = split('/',&'rnorm($_[1]));
97 &norm(&'bmul($xn,$yn),&'bmul($xd,$yd));
101 sub main'rdiv { #(rat_num, rat_num) return rat_num
102 local($xn,$xd) = split('/',&'rnorm($_[0]));
103 local($yn,$yd) = split('/',&'rnorm($_[1]));
104 &norm(&'bmul($xn,$yd),&'bmul($xd,$yn));
108 sub main'radd { #(rat_num, rat_num) return rat_num
109 local($xn,$xd) = split('/',&'rnorm($_[0]));
110 local($yn,$yd) = split('/',&'rnorm($_[1]));
111 &norm(&'badd(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd));
115 sub main'rsub { #(rat_num, rat_num) return rat_num
116 local($xn,$xd) = split('/',&'rnorm($_[0]));
117 local($yn,$yd) = split('/',&'rnorm($_[1]));
118 &norm(&'bsub(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd));
122 sub main'rcmp { #(rat_num, rat_num) return cond_code
123 local($xn,$xd) = split('/',&'rnorm($_[0]));
124 local($yn,$yd) = split('/',&'rnorm($_[1]));
125 &bigint'cmp(&'bmul($xn,$yd),&'bmul($yn,$xd));
129 sub main'rmod { #(rat_num) return (rat_num,rat_num)
130 local($xn,$xd) = split('/',&'rnorm(@_));
131 local($i,$f) = &'bdiv($xn,$xd);
139 # square root by Newtons method.
140 # cycles specifies the number of iterations default: 5
141 sub main'rsqrt { #(fnum_str[, cycles]) return fnum_str
142 local($x, $scale) = (&'rnorm($_[0]), $_[1]);
145 } elsif ($x =~ /^-/) {
148 local($gscale, $guess) = (0, '+1/1');
149 $scale = 5 if (!$scale);
150 while ($gscale++ < $scale) {
151 $guess = &'rmul(&'radd($guess,&'rdiv($x,$guess)),"+1/2");
153 "$guess"; # quotes necessary due to perl bug