ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/staticperl/perl/lib/bigrat.pl
Revision: 1.1
Committed: Thu Jun 30 14:27:08 2005 UTC (21 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: PERL-5-8-7, HEAD
Branch point for: PERL
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.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;