Upgrade to Math::BigInt v1.65, Math::BigRat v0.10,
[p5sagit/p5-mst-13.2.git] / lib / Math / BigRat.pm
1
2 #
3 # "Tax the rat farms." - Lord Vetinari
4 #
5
6 # The following hash values are used:
7 #   sign : +,-,NaN,+inf,-inf
8 #   _d   : denominator
9 #   _n   : numeraotr (value = _n/_d)
10 #   _a   : accuracy
11 #   _p   : precision
12 #   _f   : flags, used by MBR to flag parts of a rationale as untouchable
13
14 package Math::BigRat;
15
16 require 5.005_03;
17 use strict;
18
19 use Exporter;
20 use Math::BigFloat;
21 use vars qw($VERSION @ISA $PACKAGE @EXPORT_OK $upgrade $downgrade
22             $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf);
23
24 @ISA = qw(Exporter Math::BigFloat);
25 @EXPORT_OK = qw();
26
27 $VERSION = '0.10';
28
29 use overload;                   # inherit from Math::BigFloat
30
31 ##############################################################################
32 # global constants, flags and accessory
33
34 $accuracy = $precision = undef;
35 $round_mode = 'even';
36 $div_scale = 40;
37 $upgrade = undef;
38 $downgrade = undef;
39
40 # these are internally, and not to be used from the outside
41
42 use constant MB_NEVER_ROUND => 0x0001;
43
44 $_trap_nan = 0;                         # are NaNs ok? set w/ config()
45 $_trap_inf = 0;                         # are infs ok? set w/ config()
46
47 my $nan = 'NaN';
48 my $class = 'Math::BigRat';
49 my $MBI = 'Math::BigInt';
50
51 sub isa
52   {
53   return 0 if $_[1] =~ /^Math::Big(Int|Float)/;         # we aren't
54   UNIVERSAL::isa(@_);
55   }
56
57 sub _new_from_float
58   {
59   # turn a single float input into a rationale (like '0.1')
60   my ($self,$f) = @_;
61
62   return $self->bnan() if $f->is_nan();
63   return $self->binf('-inf') if $f->{sign} eq '-inf';
64   return $self->binf('+inf') if $f->{sign} eq '+inf';
65
66   $self->{_n} = $f->{_m}->copy();                       # mantissa
67   $self->{_d} = $MBI->bone();
68   $self->{sign} = $f->{sign} || '+'; $self->{_n}->{sign} = '+';
69   if ($f->{_e}->{sign} eq '-')
70     {
71     # something like Math::BigRat->new('0.1');
72     $self->{_d}->blsft($f->{_e}->copy()->babs(),10);    # 1 / 1 => 1/10
73     }
74   else
75     {
76     # something like Math::BigRat->new('10');
77     # 1 / 1 => 10/1
78     $self->{_n}->blsft($f->{_e},10) unless $f->{_e}->is_zero(); 
79     }
80   $self;
81   }
82
83 sub new
84   {
85   # create a Math::BigRat
86   my $class = shift;
87
88   my ($n,$d) = shift;
89
90   my $self = { }; bless $self,$class;
91  
92   # input like (BigInt,BigInt) or (BigFloat,BigFloat) not handled yet
93
94   if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat')))
95     {
96     if ($n->isa('Math::BigFloat'))
97       {
98       return $self->_new_from_float($n)->bnorm();
99       }
100     if ($n->isa('Math::BigInt'))
101       {
102       # TODO: trap NaN, inf
103       $self->{_n} = $n->copy();                         # "mantissa" = $n
104       $self->{_d} = $MBI->bone();
105       $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
106       return $self->bnorm();
107       }
108     if ($n->isa('Math::BigInt::Lite'))
109       {
110       # TODO: trap NaN, inf
111       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
112       $self->{_n} = $MBI->new(abs($$n),undef,undef);    # "mantissa" = $n
113       $self->{_d} = $MBI->bone();
114       return $self->bnorm();
115       }
116     }
117   return $n->copy() if ref $n;
118
119   if (!defined $n)
120     {
121     $self->{_n} = $MBI->bzero();                        # undef => 0
122     $self->{_d} = $MBI->bone();
123     $self->{sign} = '+';
124     return $self->bnorm();
125     }
126   # string input with / delimiter
127   if ($n =~ /\s*\/\s*/)
128     {
129     return $class->bnan() if $n =~ /\/.*\//;    # 1/2/3 isn't valid
130     return $class->bnan() if $n =~ /\/\s*$/;    # 1/ isn't valid
131     ($n,$d) = split (/\//,$n);
132     # try as BigFloats first
133     if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/))
134       {
135       # one of them looks like a float 
136       # Math::BigFloat($n,undef,undef) does not what it is supposed to do, so:
137       local $Math::BigFloat::accuracy = undef;
138       local $Math::BigFloat::precision = undef;
139       local $Math::BigInt::accuracy = undef;
140       local $Math::BigInt::precision = undef;
141       my $nf = Math::BigFloat->new($n);
142       $self->{sign} = '+';
143       return $self->bnan() if $nf->is_nan();
144       $self->{_n} = $nf->{_m};
145       # now correct $self->{_n} due to $n
146       my $f = Math::BigFloat->new($d,undef,undef);
147       $self->{_d} = $f->{_m};
148       return $self->bnan() if $f->is_nan();
149       #print "n=$nf e$nf->{_e} d=$f e$f->{_e}\n";
150       # calculate the difference between nE and dE
151       my $diff_e = $nf->{_e}->copy()->bsub ( $f->{_e} );
152       if ($diff_e->is_negative())
153         {
154         # < 0: mul d with it
155         $self->{_d}->blsft($diff_e->babs(),10);
156         }
157       elsif (!$diff_e->is_zero())
158         {
159         # > 0: mul n with it
160         $self->{_n}->blsft($diff_e,10);
161         }
162       }
163     else
164       {
165       # both d and n are (big)ints
166       $self->{_n} = $MBI->new($n,undef,undef);
167       $self->{_d} = $MBI->new($d,undef,undef);
168       $self->{sign} = '+';
169       return $self->bnan() if $self->{_n}->{sign} eq $nan ||
170                               $self->{_d}->{sign} eq $nan;
171       # inf handling is missing here
172       if ($self->{_n}->is_inf() || $self->{_d}->is_inf())
173         {
174         # inf/inf => NaN
175         return $self->bnan() if
176           ($self->{_n}->is_inf() && $self->{_d}->is_inf());
177         # +-inf/123 => +-inf
178         return $self->binf($self->{sign}) if $self->{_n}->is_inf();
179         # 123/inf => 0
180         return $self->bzero();
181         }
182  
183       $self->{sign} = $self->{_n}->{sign}; $self->{_n}->babs();
184       # if $d is negative, flip sign
185       $self->{sign} =~ tr/+-/-+/ if $self->{_d}->{sign} eq '-';
186       $self->{_d}->babs();                              # normalize
187       }
188
189     return $self->bnorm();
190     }
191
192   # simple string input
193   if (($n =~ /[\.eE]/))
194     {
195     # looks like a float, quacks like a float, so probably is a float
196     # Math::BigFloat($n,undef,undef) does not what it is supposed to do, so:
197     local $Math::BigFloat::accuracy = undef;
198     local $Math::BigFloat::precision = undef;
199     local $Math::BigInt::accuracy = undef;
200     local $Math::BigInt::precision = undef;
201     $self->{sign} = 'NaN';
202     $self->_new_from_float(Math::BigFloat->new($n,undef,undef));
203     }
204   else
205     {
206     $self->{_n} = $MBI->new($n,undef,undef);
207     $self->{_d} = $MBI->bone();
208     $self->{sign} = $self->{_n}->{sign}; $self->{_n}->babs();
209     return $self->bnan() if $self->{sign} eq 'NaN';
210     return $self->binf($self->{sign}) if $self->{sign} =~ /^[+-]inf$/;
211     }
212   $self->bnorm();
213   }
214
215 ##############################################################################
216
217 sub config
218   {
219   # return (later set?) configuration data as hash ref
220   my $class = shift || 'Math::BigFloat';
221
222   my $cfg = $class->SUPER::config(@_);
223
224   # now we need only to override the ones that are different from our parent
225   $cfg->{class} = $class;
226   $cfg->{with} = $MBI;
227   $cfg;
228   }
229
230 ##############################################################################
231
232 sub bstr
233   {
234   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
235
236   if ($x->{sign} !~ /^[+-]$/)           # inf, NaN etc
237     {
238     my $s = $x->{sign}; $s =~ s/^\+//;  # +inf => inf
239     return $s;
240     }
241
242   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';     # +3 vs 3
243
244   return $s.$x->{_n}->bstr() if $x->{_d}->is_one(); 
245   return $s.$x->{_n}->bstr() . '/' . $x->{_d}->bstr(); 
246   }
247
248 sub bsstr
249   {
250   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
251
252   if ($x->{sign} !~ /^[+-]$/)           # inf, NaN etc
253     {
254     my $s = $x->{sign}; $s =~ s/^\+//;  # +inf => inf
255     return $s;
256     }
257   
258   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';     # +3 vs 3
259   return $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr(); 
260   }
261
262 sub bnorm
263   {
264   # reduce the number to the shortest form and remember this (so that we
265   # don't reduce again)
266   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
267
268   # both parts must be BigInt's (or whatever we are using today)
269   if (ref($x->{_n}) ne $MBI)
270     {
271     require Carp; Carp::croak ("n is not $MBI but (".ref($x->{_n}).')');
272     }
273   if (ref($x->{_d}) ne $MBI)
274     {
275     require Carp; Carp::croak ("d is not $MBI but (".ref($x->{_d}).')');
276     }
277
278   # this is to prevent automatically rounding when MBI's globals are set
279   $x->{_d}->{_f} = MB_NEVER_ROUND;
280   $x->{_n}->{_f} = MB_NEVER_ROUND;
281   # 'forget' that parts were rounded via MBI::bround() in MBF's bfround()
282   $x->{_d}->{_a} = undef; $x->{_n}->{_a} = undef;
283   $x->{_d}->{_p} = undef; $x->{_n}->{_p} = undef; 
284
285   # no normalize for NaN, inf etc.
286   return $x if $x->{sign} !~ /^[+-]$/;
287
288   # normalize zeros to 0/1
289   if (($x->{sign} =~ /^[+-]$/) &&
290       ($x->{_n}->is_zero()))
291     {
292     $x->{sign} = '+';                                   # never -0
293     $x->{_d} = $MBI->bone() unless $x->{_d}->is_one();
294     return $x;
295     }
296
297   return $x if $x->{_d}->is_one();                      # no need to reduce
298
299   # reduce other numbers
300   # disable upgrade in BigInt, otherwise deep recursion
301   local $Math::BigInt::upgrade = undef;
302   local $Math::BigInt::accuracy = undef;
303   local $Math::BigInt::precision = undef;
304   my $gcd = $x->{_n}->bgcd($x->{_d});
305
306   if (!$gcd->is_one())
307     {
308     $x->{_n}->bdiv($gcd);
309     $x->{_d}->bdiv($gcd);
310     }
311   $x;
312   }
313
314 ##############################################################################
315 # special values
316
317 sub _bnan
318   {
319   # used by parent class bnan() to initialize number to NaN
320   my $self = shift;
321
322   if ($_trap_nan)
323     {
324     require Carp;
325     my $class = ref($self);
326     Carp::croak ("Tried to set $self to NaN in $class\::_bnan()");
327     }
328   $self->{_n} = $MBI->bzero();
329   $self->{_d} = $MBI->bzero();
330   }
331
332 sub _binf
333   {
334   # used by parent class bone() to initialize number to +inf/-inf
335   my $self = shift;
336
337   if ($_trap_inf)
338     {
339     require Carp;
340     my $class = ref($self);
341     Carp::croak ("Tried to set $self to inf in $class\::_binf()");
342     }
343   $self->{_n} = $MBI->bzero();
344   $self->{_d} = $MBI->bzero();
345   }
346
347 sub _bone
348   {
349   # used by parent class bone() to initialize number to +1/-1
350   my $self = shift;
351   $self->{_n} = $MBI->bone();
352   $self->{_d} = $MBI->bone();
353   }
354
355 sub _bzero
356   {
357   # used by parent class bzero() to initialize number to 0
358   my $self = shift;
359   $self->{_n} = $MBI->bzero();
360   $self->{_d} = $MBI->bone();
361   }
362
363 ##############################################################################
364 # mul/add/div etc
365
366 sub badd
367   {
368   # add two rationales
369
370   # set up parameters
371   my ($self,$x,$y,@r) = (ref($_[0]),@_);
372   # objectify is costly, so avoid it
373   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
374     {
375     ($self,$x,$y,@r) = objectify(2,@_);
376     }
377
378   $x = $self->new($x) unless $x->isa($self);
379   $y = $self->new($y) unless $y->isa($self);
380
381   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
382   # TODO: inf handling
383
384   #  1   1    gcd(3,4) = 1    1*3 + 1*4    7
385   #  - + -                  = --------- = --                 
386   #  4   3                      4*3       12
387
388   # we do not compute the gcd() here, but simple do:
389   #  5   7    5*3 + 7*4   41
390   #  - + -  = --------- = --                 
391   #  4   3       4*3      12
392  
393   # the gcd() calculation and reducing is then done in bnorm()
394
395   local $Math::BigInt::accuracy = undef;
396   local $Math::BigInt::precision = undef;
397
398   $x->{_n}->bmul($y->{_d}); $x->{_n}->{sign} = $x->{sign};
399   my $m = $y->{_n}->copy()->bmul($x->{_d});
400   $m->{sign} = $y->{sign};                      # 2/1 - 2/1
401   $x->{_n}->badd($m);
402
403   $x->{_d}->bmul($y->{_d});
404
405   # calculate new sign
406   $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
407
408   $x->bnorm()->round(@r);
409   }
410
411 sub bsub
412   {
413   # subtract two rationales
414
415   # set up parameters
416   my ($self,$x,$y,@r) = (ref($_[0]),@_);
417   # objectify is costly, so avoid it
418   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
419     {
420     ($self,$x,$y,@r) = objectify(2,@_);
421     }
422
423   # TODO: $self instead or $class??
424   $x = $class->new($x) unless $x->isa($class);
425   $y = $class->new($y) unless $y->isa($class);
426
427   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
428   # TODO: inf handling
429
430   #  1   1    gcd(3,4) = 1    1*3 - 1*4    7
431   #  - - -                  = --------- = --                 
432   #  4   3                      4*3       12
433   
434   # we do not compute the gcd() here, but simple do:
435   #  5   7    5*3 - 7*4     13
436   #  - - -  = --------- = - --
437   #  4   3       4*3        12
438
439   local $Math::BigInt::accuracy = undef;
440   local $Math::BigInt::precision = undef;
441
442   $x->{_n}->bmul($y->{_d}); $x->{_n}->{sign} = $x->{sign};
443   my $m = $y->{_n}->copy()->bmul($x->{_d});
444   $m->{sign} = $y->{sign};                      # 2/1 - 2/1
445   $x->{_n}->bsub($m);
446
447   $x->{_d}->bmul($y->{_d});
448   
449   # calculate new sign
450   $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
451
452   $x->bnorm()->round(@r);
453   }
454
455 sub bmul
456   {
457   # multiply two rationales
458   
459   # set up parameters
460   my ($self,$x,$y,@r) = (ref($_[0]),@_);
461   # objectify is costly, so avoid it
462   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
463     {
464     ($self,$x,$y,@r) = objectify(2,@_);
465     }
466
467   # TODO: $self instead or $class??
468   $x = $class->new($x) unless $x->isa($class);
469   $y = $class->new($y) unless $y->isa($class);
470
471   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
472
473   # inf handling
474   if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
475     {
476     return $x->bnan() if $x->is_zero() || $y->is_zero();
477     # result will always be +-inf:
478     # +inf * +/+inf => +inf, -inf * -/-inf => +inf
479     # +inf * -/-inf => -inf, -inf * +/+inf => -inf
480     return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
481     return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
482     return $x->binf('-');
483     }
484
485   # x== 0 # also: or y == 1 or y == -1
486   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
487
488   # According to Knuth, this can be optimized by doingtwice gcd (for d and n)
489   # and reducing in one step)
490
491   #  1   1    2    1
492   #  - * - =  -  = -
493   #  4   3    12   6
494   
495   local $Math::BigInt::accuracy = undef;
496   local $Math::BigInt::precision = undef;
497   $x->{_n}->bmul($y->{_n});
498   $x->{_d}->bmul($y->{_d});
499
500   # compute new sign
501   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
502
503   $x->bnorm()->round(@r);
504   }
505
506 sub bdiv
507   {
508   # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
509   # (BRAT,BRAT) (quo,rem) or BRAT (only rem)
510
511   # set up parameters
512   my ($self,$x,$y,@r) = (ref($_[0]),@_);
513   # objectify is costly, so avoid it
514   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
515     {
516     ($self,$x,$y,@r) = objectify(2,@_);
517     }
518
519   # TODO: $self instead or $class??
520   $x = $class->new($x) unless $x->isa($class);
521   $y = $class->new($y) unless $y->isa($class);
522
523   return $self->_div_inf($x,$y)
524    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
525
526   # x== 0 # also: or y == 1 or y == -1
527   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
528
529   # TODO: list context, upgrade
530
531   # 1     1    1   3
532   # -  /  - == - * -
533   # 4     3    4   1
534   
535 #  local $Math::BigInt::accuracy = undef;
536 #  local $Math::BigInt::precision = undef;
537   $x->{_n}->bmul($y->{_d});
538   $x->{_d}->bmul($y->{_n});
539
540   # compute new sign 
541   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
542
543   $x->bnorm()->round(@r);
544   $x;
545   }
546
547 sub bmod
548   {
549   # compute "remainder" (in Perl way) of $x / $y
550
551   # set up parameters
552   my ($self,$x,$y,@r) = (ref($_[0]),@_);
553   # objectify is costly, so avoid it
554   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
555     {
556     ($self,$x,$y,@r) = objectify(2,@_);
557     }
558
559   # TODO: $self instead or $class??
560   $x = $class->new($x) unless $x->isa($class);
561   $y = $class->new($y) unless $y->isa($class);
562
563   return $self->_div_inf($x,$y)
564    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
565
566   return $self->_div_inf($x,$y)
567    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
568
569   return $x if $x->is_zero();           # 0 / 7 = 0, mod 0
570
571   # compute $x - $y * floor($x/$y), keeping the sign of $x
572
573   local $Math::BigInt::upgrade = undef;
574   local $Math::BigInt::accuracy = undef;
575   local $Math::BigInt::precision = undef;
576
577   my $u = $x->copy()->babs();
578   # do a "normal" division ($x/$y)
579   $u->{_d}->bmul($y->{_n});
580   $u->{_n}->bmul($y->{_d});
581
582   # compute floor
583   if (!$u->{_d}->is_one())
584     {
585     $u->{_n}->bdiv($u->{_d});                   # 22/7 => 3/1 w/ truncate
586     # no need to set $u->{_d} to 1, since later we set it to $y->{_d}
587     #$x->{_n}->binc() if $x->{sign} eq '-';     # -22/7 => -4/1
588     }
589   
590   # compute $y * $u
591   $u->{_d} = $y->{_d};                  # 1 * $y->{_d}, see floor above
592   $u->{_n}->bmul($y->{_n});
593
594   my $xsign = $x->{sign}; $x->{sign} = '+';     # remember sign and make abs
595   # compute $x - $u
596   $x->bsub($u);
597   $x->{sign} = $xsign;                          # put sign back
598
599   $x->bnorm()->round(@r);
600   $x;
601   }
602
603 ##############################################################################
604 # bdec/binc
605
606 sub bdec
607   {
608   # decrement value (subtract 1)
609   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
610
611   return $x if $x->{sign} !~ /^[+-]$/;  # NaN, inf, -inf
612
613   if ($x->{sign} eq '-')
614     {
615     $x->{_n}->badd($x->{_d});   # -5/2 => -7/2
616     }
617   else
618     {
619     if ($x->{_n}->bacmp($x->{_d}) < 0)
620       {
621       # 1/3 -- => -2/3
622       $x->{_n} = $x->{_d} - $x->{_n};
623       $x->{sign} = '-';
624       }
625     else
626       {
627       $x->{_n}->bsub($x->{_d});         # 5/2 => 3/2
628       }
629     }
630   $x->bnorm()->round(@r);
631   }
632
633 sub binc
634   {
635   # increment value (add 1)
636   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
637   
638   return $x if $x->{sign} !~ /^[+-]$/;  # NaN, inf, -inf
639
640   if ($x->{sign} eq '-')
641     {
642     if ($x->{_n}->bacmp($x->{_d}) < 0)
643       {
644       # -1/3 ++ => 2/3 (overflow at 0)
645       $x->{_n} = $x->{_d} - $x->{_n};
646       $x->{sign} = '+';
647       }
648     else
649       {
650       $x->{_n}->bsub($x->{_d});         # -5/2 => -3/2
651       }
652     }
653   else
654     {
655     $x->{_n}->badd($x->{_d});   # 5/2 => 7/2
656     }
657   $x->bnorm()->round(@r);
658   }
659
660 ##############################################################################
661 # is_foo methods (the rest is inherited)
662
663 sub is_int
664   {
665   # return true if arg (BRAT or num_str) is an integer
666   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
667
668   return 1 if ($x->{sign} =~ /^[+-]$/) &&       # NaN and +-inf aren't
669     $x->{_d}->is_one();                         # x/y && y != 1 => no integer
670   0;
671   }
672
673 sub is_zero
674   {
675   # return true if arg (BRAT or num_str) is zero
676   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
677
678   return 1 if $x->{sign} eq '+' && $x->{_n}->is_zero();
679   0;
680   }
681
682 sub is_one
683   {
684   # return true if arg (BRAT or num_str) is +1 or -1 if signis given
685   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
686
687   my $sign = shift || ''; $sign = '+' if $sign ne '-';
688   return 1
689    if ($x->{sign} eq $sign && $x->{_n}->is_one() && $x->{_d}->is_one());
690   0;
691   }
692
693 sub is_odd
694   {
695   # return true if arg (BFLOAT or num_str) is odd or false if even
696   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
697
698   return 1 if ($x->{sign} =~ /^[+-]$/) &&               # NaN & +-inf aren't
699     ($x->{_d}->is_one() && $x->{_n}->is_odd());         # x/2 is not, but 3/1
700   0;
701   }
702
703 sub is_even
704   {
705   # return true if arg (BINT or num_str) is even or false if odd
706   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
707
708   return 0 if $x->{sign} !~ /^[+-]$/;                   # NaN & +-inf aren't
709   return 1 if ($x->{_d}->is_one()                       # x/3 is never
710      && $x->{_n}->is_even());                           # but 4/1 is
711   0;
712   }
713
714 BEGIN
715   {
716   *objectify = \&Math::BigInt::objectify;
717   }
718
719 ##############################################################################
720 # parts() and friends
721
722 sub numerator
723   {
724   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
725
726   return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
727
728   my $n = $x->{_n}->copy(); $n->{sign} = $x->{sign};
729   $n;
730   }
731
732 sub denominator
733   {
734   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
735
736   return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
737   $x->{_d}->copy(); 
738   }
739
740 sub parts
741   {
742   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
743
744   return ($self->bnan(),$self->bnan()) if $x->{sign} eq 'NaN';
745   return ($self->binf(),$self->binf()) if $x->{sign} eq '+inf';
746   return ($self->binf('-'),$self->binf()) if $x->{sign} eq '-inf';
747
748   my $n = $x->{_n}->copy();
749   $n->{sign} = $x->{sign};
750   return ($n,$x->{_d}->copy());
751   }
752
753 sub length
754   {
755   return 0;
756   }
757
758 sub digit
759   {
760   return 0;
761   }
762
763 ##############################################################################
764 # special calc routines
765
766 sub bceil
767   {
768   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
769
770   return $x unless $x->{sign} =~ /^[+-]$/;
771   return $x if $x->{_d}->is_one();              # 22/1 => 22, 0/1 => 0
772
773   local $Math::BigInt::upgrade = undef;
774   local $Math::BigInt::accuracy = undef;
775   local $Math::BigInt::precision = undef;
776   $x->{_n}->bdiv($x->{_d});                     # 22/7 => 3/1 w/ truncate
777   $x->{_d}->bone();
778   $x->{_n}->binc() if $x->{sign} eq '+';        # +22/7 => 4/1
779   $x->{sign} = '+' if $x->{_n}->is_zero();      # -0 => 0
780   $x;
781   }
782
783 sub bfloor
784   {
785   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
786
787   return $x unless $x->{sign} =~ /^[+-]$/;
788   return $x if $x->{_d}->is_one();              # 22/1 => 22, 0/1 => 0
789
790   local $Math::BigInt::upgrade = undef;
791   local $Math::BigInt::accuracy = undef;
792   local $Math::BigInt::precision = undef;
793   $x->{_n}->bdiv($x->{_d});                     # 22/7 => 3/1 w/ truncate
794   $x->{_d}->bone();
795   $x->{_n}->binc() if $x->{sign} eq '-';        # -22/7 => -4/1
796   $x;
797   }
798
799 sub bfac
800   {
801   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
802
803   if (($x->{sign} eq '+') && ($x->{_d}->is_one()))
804     {
805     $x->{_n}->bfac();
806     return $x->round(@r);
807     }
808   $x->bnan();
809   }
810
811 sub bpow
812   {
813   # power ($x ** $y)
814
815   # set up parameters
816   my ($self,$x,$y,@r) = (ref($_[0]),@_);
817   # objectify is costly, so avoid it
818   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
819     {
820     ($self,$x,$y,@r) = objectify(2,@_);
821     }
822
823   return $x if $x->{sign} =~ /^[+-]inf$/;       # -inf/+inf ** x
824   return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
825   return $x->bone(@r) if $y->is_zero();
826   return $x->round(@r) if $x->is_one() || $y->is_one();
827   if ($x->{sign} eq '-' && $x->{_n}->is_one() && $x->{_d}->is_one())
828     {
829     # if $x == -1 and odd/even y => +1/-1
830     return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
831     # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
832     }
833   # 1 ** -y => 1 / (1 ** |y|)
834   # so do test for negative $y after above's clause
835  #  return $x->bnan() if $y->{sign} eq '-';
836   return $x->round(@r) if $x->is_zero();  # 0**y => 0 (if not y <= 0)
837
838   # shortcut y/1 (and/or x/1)
839   if ($y->{_d}->is_one())
840     {
841     # shortcut for x/1 and y/1
842     if ($x->{_d}->is_one())
843       {
844       $x->{_n}->bpow($y->{_n});         # x/1 ** y/1 => (x ** y)/1
845       if ($y->{sign} eq '-')
846         {
847         # 0.2 ** -3 => 1/(0.2 ** 3)
848         ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});      # swap
849         }
850       # correct sign; + ** + => +
851       if ($x->{sign} eq '-')
852         {
853         # - * - => +, - * - * - => -
854         $x->{sign} = '+' if $y->{_n}->is_even();        
855         }
856       return $x->round(@r);
857       }
858     # x/z ** y/1
859     $x->{_n}->bpow($y->{_n});           # 5/2 ** y/1 => 5 ** y / 2 ** y
860     $x->{_d}->bpow($y->{_n});
861     if ($y->{sign} eq '-')
862       {
863       # 0.2 ** -3 => 1/(0.2 ** 3)
864       ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});        # swap
865       }
866     # correct sign; + ** + => +
867     if ($x->{sign} eq '-')
868       {
869       # - * - => +, - * - * - => -
870       $x->{sign} = '+' if $y->{_n}->is_even();  
871       }
872     return $x->round(@r);
873     }
874
875   # regular calculation (this is wrong for d/e ** f/g)
876   my $pow2 = $self->__one();
877   my $y1 = $MBI->new($y->{_n}/$y->{_d})->babs();
878   my $two = $MBI->new(2);
879   while (!$y1->is_one())
880     {
881     $pow2->bmul($x) if $y1->is_odd();
882     $y1->bdiv($two);
883     $x->bmul($x);
884     }
885   $x->bmul($pow2) unless $pow2->is_one();
886   # n ** -x => 1/n ** x
887   ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-'; 
888   $x->bnorm()->round(@r);
889   }
890
891 sub blog
892   {
893   return Math::BigRat->bnan();
894   }
895
896 sub bsqrt
897   {
898   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
899
900   return $x->bnan() if $x->{sign} !~ /^[+]/;    # NaN, -inf or < 0
901   return $x if $x->{sign} eq '+inf';            # sqrt(inf) == inf
902   return $x->round(@r) if $x->is_zero() || $x->is_one();
903
904   local $Math::BigFloat::upgrade = undef;
905   local $Math::BigFloat::downgrade = undef;
906   local $Math::BigFloat::precision = undef;
907   local $Math::BigFloat::accuracy = undef;
908   local $Math::BigInt::upgrade = undef;
909   local $Math::BigInt::precision = undef;
910   local $Math::BigInt::accuracy = undef;
911   $x->{_d} = Math::BigFloat->new($x->{_d})->bsqrt(@r);
912   $x->{_n} = Math::BigFloat->new($x->{_n})->bsqrt(@r);
913
914   # if sqrt(D) was not integer
915   if ($x->{_d}->{_e}->{sign} ne '+')
916     {
917     $x->{_n}->blsft($x->{_d}->{_e}->babs(),10);         # 7.1/4.51 => 7.1/45.1
918     $x->{_d} = $x->{_d}->{_m};                          # 7.1/45.1 => 71/45.1
919     }
920   # if sqrt(N) was not integer
921   if ($x->{_n}->{_e}->{sign} ne '+')
922     {
923     $x->{_d}->blsft($x->{_n}->{_e}->babs(),10);         # 71/45.1 => 710/45.1
924     $x->{_n} = $x->{_n}->{_n};                          # 710/45.1 => 710/451
925     }
926  
927   # convert parts to $MBI again 
928   $x->{_n} = $x->{_n}->as_number();
929   $x->{_d} = $x->{_d}->as_number();
930   $x->bnorm()->round(@r);
931   }
932
933 sub blsft
934   {
935   my ($self,$x,$y,$b,$a,$p,$r) = objectify(3,@_);
936  
937   $x->bmul( $b->copy()->bpow($y), $a,$p,$r);
938   $x;
939   }
940
941 sub brsft
942   {
943   my ($self,$x,$y,$b,$a,$p,$r) = objectify(2,@_);
944
945   $x->bdiv( $b->copy()->bpow($y), $a,$p,$r);
946   $x;
947   }
948
949 ##############################################################################
950 # round
951
952 sub round
953   {
954   $_[0];
955   }
956
957 sub bround
958   {
959   $_[0];
960   }
961
962 sub bfround
963   {
964   $_[0];
965   }
966
967 ##############################################################################
968 # comparing
969
970 sub bcmp
971   {
972   my ($self,$x,$y) = objectify(2,@_);
973
974   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
975     {
976     # handle +-inf and NaN
977     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
978     return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
979     return +1 if $x->{sign} eq '+inf';
980     return -1 if $x->{sign} eq '-inf';
981     return -1 if $y->{sign} eq '+inf';
982     return +1;
983     }
984   # check sign for speed first
985   return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';   # does also 0 <=> -y
986   return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';  # does also -x <=> 0
987
988   # shortcut
989   my $xz = $x->{_n}->is_zero();
990   my $yz = $y->{_n}->is_zero();
991   return 0 if $xz && $yz;                               # 0 <=> 0
992   return -1 if $xz && $y->{sign} eq '+';                # 0 <=> +y
993   return 1 if $yz && $x->{sign} eq '+';                 # +x <=> 0
994  
995   my $t = $x->{_n} * $y->{_d}; $t->{sign} = $x->{sign};
996   my $u = $y->{_n} * $x->{_d}; $u->{sign} = $y->{sign};
997   $t->bcmp($u);
998   }
999
1000 sub bacmp
1001   {
1002   my ($self,$x,$y) = objectify(2,@_);
1003
1004   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1005     {
1006     # handle +-inf and NaN
1007     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1008     return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
1009     return +1;  # inf is always bigger
1010     }
1011
1012   my $t = $x->{_n} * $y->{_d};
1013   my $u = $y->{_n} * $x->{_d};
1014   $t->bacmp($u);
1015   }
1016
1017 ##############################################################################
1018 # output conversation
1019
1020 sub numify
1021   {
1022   # convert 17/8 => float (aka 2.125)
1023   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
1024  
1025   return $x->bstr() if $x->{sign} !~ /^[+-]$/;  # inf, NaN, etc
1026
1027   my $t = Math::BigFloat->new($x->{_n});
1028   $t->bneg() if $x->is_negative();
1029   $t->bdiv($x->{_d});
1030   $t->numify();  
1031   }
1032
1033 sub as_number
1034   {
1035   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
1036
1037   return $x if $x->{sign} !~ /^[+-]$/;                  # NaN, inf etc
1038  
1039   # need to disable these, otherwise bdiv() gives BigRat again
1040   local $Math::BigInt::upgrade = undef;
1041   local $Math::BigInt::accuracy = undef;
1042   local $Math::BigInt::precision = undef;
1043   my $t = $x->{_n}->copy()->bdiv($x->{_d});             # 22/7 => 3
1044   $t->{sign} = $x->{sign};
1045   $t;
1046   }
1047
1048 sub import
1049   {
1050   my $self = shift;
1051   my $l = scalar @_;
1052   my $lib = ''; my @a;
1053   for ( my $i = 0; $i < $l ; $i++)
1054     {
1055 #    print "at $_[$i] (",$_[$i+1]||'undef',")\n";
1056     if ( $_[$i] eq ':constant' )
1057       {
1058       # this rest causes overlord er load to step in
1059       # print "overload @_\n";
1060       overload::constant float => sub { $self->new(shift); };
1061       }
1062 #    elsif ($_[$i] eq 'upgrade')
1063 #      {
1064 #     # this causes upgrading
1065 #      $upgrade = $_[$i+1];              # or undef to disable
1066 #      $i++;
1067 #      }
1068     elsif ($_[$i] eq 'downgrade')
1069       {
1070       # this causes downgrading
1071       $downgrade = $_[$i+1];            # or undef to disable
1072       $i++;
1073       }
1074     elsif ($_[$i] eq 'lib')
1075       {
1076       $lib = $_[$i+1] || '';            # default Calc
1077       $i++;
1078       }
1079     elsif ($_[$i] eq 'with')
1080       {
1081       $MBI = $_[$i+1] || 'Math::BigInt';        # default Math::BigInt
1082       $i++;
1083       }
1084     else
1085       {
1086       push @a, $_[$i];
1087       }
1088     }
1089   # let use Math::BigInt lib => 'GMP'; use Math::BigFloat; still work
1090   my $mbilib = eval { Math::BigInt->config()->{lib} };
1091   if ((defined $mbilib) && ($MBI eq 'Math::BigInt'))
1092     {
1093     # MBI already loaded
1094     $MBI->import('lib',"$lib,$mbilib", 'objectify');
1095     }
1096   else
1097     {
1098     # MBI not loaded, or not with "Math::BigInt"
1099     $lib .= ",$mbilib" if defined $mbilib;
1100
1101     if ($] < 5.006)
1102       {
1103       # Perl < 5.6.0 dies with "out of memory!" when eval() and ':constant' is
1104       # used in the same script, or eval inside import().
1105       my @parts = split /::/, $MBI;             # Math::BigInt => Math BigInt
1106       my $file = pop @parts; $file .= '.pm';    # BigInt => BigInt.pm
1107       $file = File::Spec->catfile (@parts, $file);
1108       eval { require $file; $MBI->import( lib => '$lib', 'objectify' ); }
1109       }
1110     else
1111       {
1112       my $rc = "use $MBI lib => '$lib', 'objectify';";
1113       eval $rc;
1114       }
1115     }
1116   die ("Couldn't load $MBI: $! $@") if $@;
1117
1118   # any non :constant stuff is handled by our parent, Exporter
1119   # even if @_ is empty, to give it a chance
1120   $self->SUPER::import(@a);             # for subclasses
1121   $self->export_to_level(1,$self,@a);   # need this, too
1122   }
1123
1124 1;
1125
1126 __END__
1127
1128 =head1 NAME
1129
1130 Math::BigRat - arbitrarily big rationales
1131
1132 =head1 SYNOPSIS
1133
1134         use Math::BigRat;
1135
1136         $x = Math::BigRat->new('3/7'); $x += '5/9';
1137
1138         print $x->bstr(),"\n";
1139         print $x ** 2,"\n";
1140
1141 =head1 DESCRIPTION
1142
1143 Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
1144 for arbitrarily big rationales.
1145
1146 =head2 MATH LIBRARY
1147
1148 Math with the numbers is done (by default) by a module called
1149 Math::BigInt::Calc. This is equivalent to saying:
1150
1151         use Math::BigRat lib => 'Calc';
1152
1153 You can change this by using:
1154
1155         use Math::BigRat lib => 'BitVect';
1156
1157 The following would first try to find Math::BigInt::Foo, then
1158 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
1159
1160         use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
1161
1162 Calc.pm uses as internal format an array of elements of some decimal base
1163 (usually 1e7, but this might be different for some systems) with the least
1164 significant digit first, while BitVect.pm uses a bit vector of base 2, most
1165 significant bit first. Other modules might use even different means of
1166 representing the numbers. See the respective module documentation for further
1167 details.
1168
1169 Currently the following replacement libraries exist, search for them at CPAN:
1170
1171         Math::BigInt::BitVect
1172         Math::BigInt::GMP
1173         Math::BigInt::Pari
1174         Math::BigInt::FastCalc
1175
1176 =head1 METHODS
1177
1178 Any methods not listed here are dervied from Math::BigFloat (or
1179 Math::BigInt), so make sure you check these two modules for further
1180 information.
1181
1182 =head2 new()
1183
1184         $x = Math::BigRat->new('1/3');
1185
1186 Create a new Math::BigRat object. Input can come in various forms:
1187
1188         $x = Math::BigRat->new(123);                            # scalars
1189         $x = Math::BigRat->new('123.3');                        # float
1190         $x = Math::BigRat->new('1/3');                          # simple string
1191         $x = Math::BigRat->new('1 / 3');                        # spaced
1192         $x = Math::BigRat->new('1 / 0.1');                      # w/ floats
1193         $x = Math::BigRat->new(Math::BigInt->new(3));           # BigInt
1194         $x = Math::BigRat->new(Math::BigFloat->new('3.1'));     # BigFloat
1195         $x = Math::BigRat->new(Math::BigInt::Lite->new('2'));   # BigLite
1196
1197 =head2 numerator()
1198
1199         $n = $x->numerator();
1200
1201 Returns a copy of the numerator (the part above the line) as signed BigInt.
1202
1203 =head2 denominator()
1204         
1205         $d = $x->denominator();
1206
1207 Returns a copy of the denominator (the part under the line) as positive BigInt.
1208
1209 =head2 parts()
1210
1211         ($n,$d) = $x->parts();
1212
1213 Return a list consisting of (signed) numerator and (unsigned) denominator as
1214 BigInts.
1215
1216 =head2 as_number()
1217
1218         $x = Math::BigRat->new('13/7');
1219         print $x->as_number(),"\n";             # '1'
1220
1221 Returns a copy of the object as BigInt trunced it to integer.
1222
1223 =head2 bfac()
1224
1225         $x->bfac();
1226
1227 Calculates the factorial of $x. For instance:
1228
1229         print Math::BigRat->new('3/1')->bfac(),"\n";    # 1*2*3
1230         print Math::BigRat->new('5/1')->bfac(),"\n";    # 1*2*3*4*5
1231
1232 Works currently only for integers.
1233
1234 =head2 blog()
1235
1236 Is not yet implemented.
1237
1238 =head2 bround()/round()/bfround()
1239
1240 Are not yet implemented.
1241
1242 =head2 bmod()
1243
1244         use Math::BigRat;
1245         my $x = Math::BigRat->new('7/4');
1246         my $y = Math::BigRat->new('4/3');
1247         print $x->bmod($y);
1248
1249 Set $x to the remainder of the division of $x by $y.
1250
1251 =head2 is_one()
1252
1253         print "$x is 1\n" if $x->is_one();
1254
1255 Return true if $x is exactly one, otherwise false.
1256
1257 =head2 is_zero()
1258
1259         print "$x is 0\n" if $x->is_zero();
1260
1261 Return true if $x is exactly zero, otherwise false.
1262
1263 =head2 is_positive()
1264
1265         print "$x is >= 0\n" if $x->is_positive();
1266
1267 Return true if $x is positive (greater than or equal to zero), otherwise
1268 false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
1269
1270 =head2 is_negative()
1271
1272         print "$x is < 0\n" if $x->is_negative();
1273
1274 Return true if $x is negative (smaller than zero), otherwise false. Please
1275 note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
1276
1277 =head2 is_int()
1278
1279         print "$x is an integer\n" if $x->is_int();
1280
1281 Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
1282 false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
1283
1284 =head2 is_odd()
1285
1286         print "$x is odd\n" if $x->is_odd();
1287
1288 Return true if $x is odd, otherwise false.
1289
1290 =head2 is_even()
1291
1292         print "$x is even\n" if $x->is_even();
1293
1294 Return true if $x is even, otherwise false.
1295
1296 =head2 bceil()
1297
1298         $x->bceil();
1299
1300 Set $x to the next bigger integer value (e.g. truncate the number to integer
1301 and then increment it by one).
1302
1303 =head2 bfloor()
1304         
1305         $x->bfloor();
1306
1307 Truncate $x to an integer value.
1308
1309 =head2 config
1310
1311         use Data::Dumper;
1312
1313         print Dumper ( Math::BigRat->config() );
1314         print Math::BigRat->config()->{lib},"\n";
1315
1316 Returns a hash containing the configuration, e.g. the version number, lib
1317 loaded etc. The following hash keys are currently filled in with the
1318 appropriate information.
1319
1320         key             RO/RW   Description
1321                                 Example
1322         ============================================================
1323         lib             RO      Name of the Math library
1324                                 Math::BigInt::Calc
1325         lib_version     RO      Version of 'lib'
1326                                 0.30
1327         class           RO      The class of config you just called
1328                                 Math::BigRat
1329         version         RO      version number of the class you used
1330                                 0.10
1331         upgrade         RW      To which class numbers are upgraded
1332                                 undef
1333         downgrade       RW      To which class numbers are downgraded
1334                                 undef
1335         precision       RW      Global precision
1336                                 undef
1337         accuracy        RW      Global accuracy
1338                                 undef
1339         round_mode      RW      Global round mode
1340                                 even
1341         div_scale       RW      Fallback acccuracy for div
1342                                 40
1343         trap_nan        RW      Trap creation of NaN (undef = no)
1344                                 undef
1345         trap_inf        RW      Trap creation of +inf/-inf (undef = no)
1346                                 undef
1347
1348 By passing a reference to a hash you may set the configuration values. This
1349 works only for values that a marked with a C<RW> above, anything else is
1350 read-only.
1351
1352 =head1 BUGS
1353
1354 Some things are not yet implemented, or only implemented half-way:
1355
1356 =over 2
1357
1358 =item inf handling (partial)
1359
1360 =item NaN handling (partial)
1361
1362 =item rounding (not implemented except for bceil/bfloor)
1363
1364 =item $x ** $y where $y is not an integer
1365
1366 =back
1367
1368 =head1 LICENSE
1369
1370 This program is free software; you may redistribute it and/or modify it under
1371 the same terms as Perl itself.
1372
1373 =head1 SEE ALSO
1374
1375 L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
1376 L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
1377
1378 See L<http://search.cpan.org/search?dist=bignum> for a way to use
1379 Math::BigRat.
1380
1381 The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
1382 may contain more documentation and examples as well as testcases.
1383
1384 =head1 AUTHORS
1385
1386 (C) by Tels L<http://bloodgate.com/> 2001-2002. 
1387
1388 =cut