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