source: for-distributions/trunk/bin/windows/perl/lib/bigrat.pl@ 14489

Last change on this file since 14489 was 14489, checked in by oranfry, 17 years ago

upgrading to perl 5.8

File size: 4.4 KB
Line 
1package bigrat;
2require "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
43# Convert a number to the canonical string form m|^[+-]\d+/\d+|.
44sub main'rnorm { #(string) return rat_num
45 local($_) = @_;
46 s/\s+//g;
47 if (m#^([+-]?\d+)(/(\d*[1-9]0*))?$#) {
48 &norm($1, $3 ? $3 : '+1');
49 } else {
50 'NaN';
51 }
52}
53
54# Normalize by reducing to lowest terms
55sub norm { #(bint, bint) return rat_num
56 local($num,$dom) = @_;
57 if ($num eq 'NaN') {
58 'NaN';
59 } elsif ($dom eq 'NaN') {
60 'NaN';
61 } elsif ($dom =~ /^[+-]?0+$/) {
62 'NaN';
63 } else {
64 local($gcd) = &'bgcd($num,$dom);
65 $gcd =~ s/^-/+/;
66 if ($gcd ne '+1') {
67 $num = &'bdiv($num,$gcd);
68 $dom = &'bdiv($dom,$gcd);
69 } else {
70 $num = &'bnorm($num);
71 $dom = &'bnorm($dom);
72 }
73 substr($dom,$[,1) = '';
74 "$num/$dom";
75 }
76}
77
78# negation
79sub main'rneg { #(rat_num) return rat_num
80 local($_) = &'rnorm(@_);
81 tr/-+/+-/ if ($_ ne '+0/1');
82 $_;
83}
84
85# absolute value
86sub main'rabs { #(rat_num) return $rat_num
87 local($_) = &'rnorm(@_);
88 substr($_,$[,1) = '+' unless $_ eq 'NaN';
89 $_;
90}
91
92# multipication
93sub main'rmul { #(rat_num, rat_num) return rat_num
94 local($xn,$xd) = split('/',&'rnorm($_[$[]));
95 local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
96 &norm(&'bmul($xn,$yn),&'bmul($xd,$yd));
97}
98
99# division
100sub main'rdiv { #(rat_num, rat_num) return rat_num
101 local($xn,$xd) = split('/',&'rnorm($_[$[]));
102 local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
103 &norm(&'bmul($xn,$yd),&'bmul($xd,$yn));
104}
105
106
107# addition
108sub main'radd { #(rat_num, rat_num) return rat_num
109 local($xn,$xd) = split('/',&'rnorm($_[$[]));
110 local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
111 &norm(&'badd(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd));
112}
113
114# subtraction
115sub main'rsub { #(rat_num, rat_num) return rat_num
116 local($xn,$xd) = split('/',&'rnorm($_[$[]));
117 local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
118 &norm(&'bsub(&'bmul($xn,$yd),&'bmul($yn,$xd)),&'bmul($xd,$yd));
119}
120
121# comparison
122sub main'rcmp { #(rat_num, rat_num) return cond_code
123 local($xn,$xd) = split('/',&'rnorm($_[$[]));
124 local($yn,$yd) = split('/',&'rnorm($_[$[+1]));
125 &bigint'cmp(&'bmul($xn,$yd),&'bmul($yn,$xd));
126}
127
128# int and frac parts
129sub main'rmod { #(rat_num) return (rat_num,rat_num)
130 local($xn,$xd) = split('/',&'rnorm(@_));
131 local($i,$f) = &'bdiv($xn,$xd);
132 if (wantarray) {
133 ("$i/1", "$f/$xd");
134 } else {
135 "$i/1";
136 }
137}
138
139# square root by Newtons method.
140# cycles specifies the number of iterations default: 5
141sub main'rsqrt { #(fnum_str[, cycles]) return fnum_str
142 local($x, $scale) = (&'rnorm($_[$[]), $_[$[+1]);
143 if ($x eq 'NaN') {
144 'NaN';
145 } elsif ($x =~ /^-/) {
146 'NaN';
147 } else {
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");
152 }
153 "$guess"; # quotes necessary due to perl bug
154 }
155}
156
1571;
Note: See TracBrowser for help on using the repository browser.