3 # "Tax the rat farms." - Lord Vetinari
6 # The following hash values are used:
7 # sign : +,-,NaN,+inf,-inf
9 # _n : numeraotr (value = _n/_d)
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.
22 use vars qw($VERSION @ISA $PACKAGE $upgrade $downgrade
23 $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf);
25 @ISA = qw(Exporter Math::BigFloat);
29 use overload; # inherit from Math::BigFloat
31 BEGIN { *objectify = \&Math::BigInt::objectify; }
33 ##############################################################################
34 # global constants, flags and accessory
36 $accuracy = $precision = undef;
42 # these are internally, and not to be used from the outside
44 use constant MB_NEVER_ROUND => 0x0001;
46 $_trap_nan = 0; # are NaNs ok? set w/ config()
47 $_trap_inf = 0; # are infs ok? set w/ config()
50 my $MBI = 'Math::BigInt';
51 my $CALC = 'Math::BigInt::Calc';
52 my $class = 'Math::BigRat';
57 return 0 if $_[1] =~ /^Math::Big(Int|Float)/; # we aren't
63 *AUTOLOAD = \&Math::BigFloat::AUTOLOAD;
68 # turn a single float input into a rational number (like '0.1')
71 return $self->bnan() if $f->is_nan();
72 return $self->binf($f->{sign}) if $f->{sign} =~ /^[+-]inf$/;
74 local $Math::BigInt::accuracy = undef;
75 local $Math::BigInt::precision = undef;
76 $self->{_n} = $MBI->new($CALC->_str ( $f->{_m} ),undef,undef);# mantissa
77 $self->{_d} = $MBI->bone();
78 $self->{sign} = $f->{sign} || '+';
81 # something like Math::BigRat->new('0.1');
83 $self->{_d}->blsft( $MBI->new($CALC->_str ( $f->{_e} )),10);
87 # something like Math::BigRat->new('10');
89 $self->{_n}->blsft( $MBI->new($CALC->_str($f->{_e})),10) unless
90 $CALC->_is_zero($f->{_e});
97 # create a Math::BigRat
102 my $self = { }; bless $self,$class;
104 # input like (BigInt,BigInt) or (BigFloat,BigFloat) not handled yet
106 if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat')))
108 if ($n->isa('Math::BigFloat'))
110 $self->_new_from_float($n);
112 if ($n->isa('Math::BigInt'))
114 # TODO: trap NaN, inf
115 $self->{_n} = $n->copy(); # "mantissa" = $n
116 $self->{_d} = $MBI->bone();
117 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
119 if ($n->isa('Math::BigInt::Lite'))
121 # TODO: trap NaN, inf
122 $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
123 $self->{_n} = $MBI->new(abs($$n),undef,undef); # "mantissa" = $n
124 $self->{_d} = $MBI->bone();
126 return $self->bnorm();
128 return $n->copy() if ref $n;
132 $self->{_n} = $MBI->bzero(); # undef => 0
133 $self->{_d} = $MBI->bone();
135 return $self->bnorm();
137 # string input with / delimiter
138 if ($n =~ /\s*\/\s*/)
140 return $class->bnan() if $n =~ /\/.*\//; # 1/2/3 isn't valid
141 return $class->bnan() if $n =~ /\/\s*$/; # 1/ isn't valid
142 ($n,$d) = split (/\//,$n);
143 # try as BigFloats first
144 if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/))
146 # one of them looks like a float
147 # Math::BigFloat($n,undef,undef) does not what it is supposed to do, so:
148 local $Math::BigFloat::accuracy = undef;
149 local $Math::BigFloat::precision = undef;
150 local $Math::BigInt::accuracy = undef;
151 local $Math::BigInt::precision = undef;
153 my $nf = Math::BigFloat->new($n,undef,undef);
155 return $self->bnan() if $nf->is_nan();
156 $self->{_n} = $MBI->new( $CALC->_str( $nf->{_m} ) );
158 # now correct $self->{_n} due to $n
159 my $f = Math::BigFloat->new($d,undef,undef);
160 return $self->bnan() if $f->is_nan();
161 $self->{_d} = $MBI->new( $CALC->_str( $f->{_m} ) );
163 # calculate the difference between nE and dE
164 my $diff_e = $MBI->new ($nf->exponent())->bsub ( $f->exponent);
165 if ($diff_e->is_negative())
168 $self->{_d}->blsft($diff_e->babs(),10);
170 elsif (!$diff_e->is_zero())
173 $self->{_n}->blsft($diff_e,10);
178 # both d and n are (big)ints
179 $self->{_n} = $MBI->new($n,undef,undef);
180 $self->{_d} = $MBI->new($d,undef,undef);
182 return $self->bnan() if $self->{_n}->{sign} eq $nan ||
183 $self->{_d}->{sign} eq $nan;
184 # handle inf and NAN cases:
185 if ($self->{_n}->is_inf() || $self->{_d}->is_inf())
188 return $self->bnan() if
189 ($self->{_n}->is_inf() && $self->{_d}->is_inf());
190 if ($self->{_n}->is_inf())
192 my $s = '+'; # '+inf/+123' or '-inf/-123'
193 $s = '-' if substr($self->{_n}->{sign},0,1) ne $self->{_d}->{sign};
195 return $self->binf($s);
198 return $self->bzero();
201 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->babs();
202 # if $d is negative, flip sign
203 $self->{sign} =~ tr/+-/-+/ if $self->{_d}->{sign} eq '-';
204 $self->{_d}->babs(); # normalize
207 return $self->bnorm();
210 # simple string input
211 if (($n =~ /[\.eE]/))
213 # looks like a float, quacks like a float, so probably is a float
214 # Math::BigFloat($n,undef,undef) does not what it is supposed to do, so:
215 local $Math::BigFloat::accuracy = undef;
216 local $Math::BigFloat::precision = undef;
217 local $Math::BigInt::accuracy = undef;
218 local $Math::BigInt::precision = undef;
219 $self->{sign} = 'NaN';
220 $self->_new_from_float(Math::BigFloat->new($n,undef,undef));
224 $self->{_n} = $MBI->new($n,undef,undef);
225 $self->{_d} = $MBI->bone();
226 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->babs();
227 return $self->bnan() if $self->{sign} eq 'NaN';
228 return $self->binf($self->{sign}) if $self->{sign} =~ /^[+-]inf$/;
238 # if two arguments, the first one is the class to "swallow" subclasses
246 return unless ref($x); # only for objects
248 my $self = {}; bless $self,$c;
250 $self->{sign} = $x->{sign};
251 $self->{_d} = $x->{_d}->copy();
252 $self->{_n} = $x->{_n}->copy();
253 $self->{_a} = $x->{_a} if defined $x->{_a};
254 $self->{_p} = $x->{_p} if defined $x->{_p};
258 ##############################################################################
262 # return (later set?) configuration data as hash ref
263 my $class = shift || 'Math::BigFloat';
265 my $cfg = $class->SUPER::config(@_);
267 # now we need only to override the ones that are different from our parent
268 $cfg->{class} = $class;
273 ##############################################################################
277 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
279 if ($x->{sign} !~ /^[+-]$/) # inf, NaN etc
281 my $s = $x->{sign}; $s =~ s/^\+//; # +inf => inf
285 my $s = ''; $s = $x->{sign} if $x->{sign} ne '+'; # '+3/2' => '3/2'
287 return $s . $x->{_n}->bstr() if $x->{_d}->is_one();
288 $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr();
293 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
295 if ($x->{sign} !~ /^[+-]$/) # inf, NaN etc
297 my $s = $x->{sign}; $s =~ s/^\+//; # +inf => inf
301 my $s = ''; $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3
302 $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr();
307 # reduce the number to the shortest form and remember this (so that we
308 # don't reduce again)
309 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
311 # both parts must be BigInt's (or whatever we are using today)
312 if (ref($x->{_n}) ne $MBI)
314 require Carp; Carp::croak ("n is not $MBI but (".ref($x->{_n}).')');
316 if (ref($x->{_d}) ne $MBI)
318 require Carp; Carp::croak ("d is not $MBI but (".ref($x->{_d}).')');
321 # this is to prevent automatically rounding when MBI's globals are set
322 $x->{_d}->{_f} = MB_NEVER_ROUND;
323 $x->{_n}->{_f} = MB_NEVER_ROUND;
324 # 'forget' that parts were rounded via MBI::bround() in MBF's bfround()
325 delete $x->{_d}->{_a}; delete $x->{_n}->{_a};
326 delete $x->{_d}->{_p}; delete $x->{_n}->{_p};
328 # no normalize for NaN, inf etc.
329 return $x if $x->{sign} !~ /^[+-]$/;
331 # normalize zeros to 0/1
332 if (($x->{sign} =~ /^[+-]$/) &&
333 ($x->{_n}->is_zero()))
335 $x->{sign} = '+'; # never -0
336 $x->{_d} = $MBI->bone() unless $x->{_d}->is_one();
340 return $x if $x->{_d}->is_one(); # no need to reduce
342 # reduce other numbers
343 # disable upgrade in BigInt, otherwise deep recursion
344 local $Math::BigInt::upgrade = undef;
345 local $Math::BigInt::accuracy = undef;
346 local $Math::BigInt::precision = undef;
347 my $gcd = $x->{_n}->bgcd($x->{_d});
351 $x->{_n}->bdiv($gcd);
352 $x->{_d}->bdiv($gcd);
357 ##############################################################################
362 # used by parent class bnan() to initialize number to NaN
368 my $class = ref($self);
369 Carp::croak ("Tried to set $self to NaN in $class\::_bnan()");
371 $self->{_n} = $MBI->bzero();
372 $self->{_d} = $MBI->bzero();
377 # used by parent class bone() to initialize number to +inf/-inf
383 my $class = ref($self);
384 Carp::croak ("Tried to set $self to inf in $class\::_binf()");
386 $self->{_n} = $MBI->bzero();
387 $self->{_d} = $MBI->bzero();
392 # used by parent class bone() to initialize number to +1/-1
394 $self->{_n} = $MBI->bone();
395 $self->{_d} = $MBI->bone();
400 # used by parent class bzero() to initialize number to 0
402 $self->{_n} = $MBI->bzero();
403 $self->{_d} = $MBI->bone();
406 ##############################################################################
411 # add two rational numbers
414 my ($self,$x,$y,@r) = (ref($_[0]),@_);
415 # objectify is costly, so avoid it
416 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
418 ($self,$x,$y,@r) = objectify(2,@_);
421 $x = $self->new($x) unless $x->isa($self);
422 $y = $self->new($y) unless $y->isa($self);
424 return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
427 # 1 1 gcd(3,4) = 1 1*3 + 1*4 7
428 # - + - = --------- = --
431 # we do not compute the gcd() here, but simple do:
433 # - + - = --------- = --
436 # the gcd() calculation and reducing is then done in bnorm()
438 local $Math::BigInt::accuracy = undef;
439 local $Math::BigInt::precision = undef;
441 $x->{_n}->bmul($y->{_d}); $x->{_n}->{sign} = $x->{sign};
442 my $m = $y->{_n}->copy()->bmul($x->{_d});
443 $m->{sign} = $y->{sign}; # 2/1 - 2/1
446 $x->{_d}->bmul($y->{_d});
448 # calculate sign of result and norm our _n part
449 $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
451 $x->bnorm()->round(@r);
456 # subtract two rational numbers
459 my ($self,$x,$y,@r) = (ref($_[0]),@_);
460 # objectify is costly, so avoid it
461 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
463 ($self,$x,$y,@r) = objectify(2,@_);
466 # flip sign of $x, call badd(), then flip sign of result
467 $x->{sign} =~ tr/+-/-+/
468 unless $x->{sign} eq '+' && $x->{_n}->is_zero(); # not -0
469 $x->badd($y,@r); # does norm and round
470 $x->{sign} =~ tr/+-/-+/
471 unless $x->{sign} eq '+' && $x->{_n}->is_zero(); # not -0
477 # multiply two rational numbers
480 my ($self,$x,$y,@r) = (ref($_[0]),@_);
481 # objectify is costly, so avoid it
482 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
484 ($self,$x,$y,@r) = objectify(2,@_);
487 $x = $self->new($x) unless $x->isa($self);
488 $y = $self->new($y) unless $y->isa($self);
490 return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
493 if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
495 return $x->bnan() if $x->is_zero() || $y->is_zero();
496 # result will always be +-inf:
497 # +inf * +/+inf => +inf, -inf * -/-inf => +inf
498 # +inf * -/-inf => -inf, -inf * +/+inf => -inf
499 return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
500 return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
501 return $x->binf('-');
504 # x== 0 # also: or y == 1 or y == -1
505 return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
507 # According to Knuth, this can be optimized by doingtwice gcd (for d and n)
508 # and reducing in one step)
514 local $Math::BigInt::accuracy = undef;
515 local $Math::BigInt::precision = undef;
516 $x->{_n}->bmul($y->{_n});
517 $x->{_d}->bmul($y->{_d});
520 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
522 $x->bnorm()->round(@r);
527 # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
528 # (BRAT,BRAT) (quo,rem) or BRAT (only rem)
531 my ($self,$x,$y,@r) = (ref($_[0]),@_);
532 # objectify is costly, so avoid it
533 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
535 ($self,$x,$y,@r) = objectify(2,@_);
538 $x = $self->new($x) unless $x->isa($self);
539 $y = $self->new($y) unless $y->isa($self);
541 return $self->_div_inf($x,$y)
542 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
544 # x== 0 # also: or y == 1 or y == -1
545 return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
547 # TODO: list context, upgrade
553 local $Math::BigInt::accuracy = undef;
554 local $Math::BigInt::precision = undef;
555 $x->{_n}->bmul($y->{_d});
556 $x->{_d}->bmul($y->{_n});
559 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
561 $x->bnorm()->round(@r);
567 # compute "remainder" (in Perl way) of $x / $y
570 my ($self,$x,$y,@r) = (ref($_[0]),@_);
571 # objectify is costly, so avoid it
572 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
574 ($self,$x,$y,@r) = objectify(2,@_);
577 $x = $self->new($x) unless $x->isa($self);
578 $y = $self->new($y) unless $y->isa($self);
580 return $self->_div_inf($x,$y)
581 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
583 return $self->_div_inf($x,$y)
584 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
586 return $x if $x->is_zero(); # 0 / 7 = 0, mod 0
588 # compute $x - $y * floor($x/$y), keeping the sign of $x
590 # locally disable these, since they would interfere
591 local $Math::BigInt::upgrade = undef;
592 local $Math::BigInt::accuracy = undef;
593 local $Math::BigInt::precision = undef;
595 my $u = $x->copy()->babs();
596 # first, do a "normal" division ($x/$y)
597 $u->{_d}->bmul($y->{_n});
598 $u->{_n}->bmul($y->{_d});
601 if (!$u->{_d}->is_one())
603 $u->{_n}->bdiv($u->{_d}); # 22/7 => 3/1 w/ truncate
604 # no need to set $u->{_d} to 1, since later we set it to $y->{_d}
605 #$x->{_n}->binc() if $x->{sign} eq '-'; # -22/7 => -4/1
609 $u->{_d} = $y->{_d}; # 1 * $y->{_d}, see floor above
610 $u->{_n}->bmul($y->{_n});
612 my $xsign = $x->{sign}; $x->{sign} = '+'; # remember sign and make abs
615 $x->{sign} = $xsign; # put sign back
617 $x->bnorm()->round(@r);
620 ##############################################################################
625 # decrement value (subtract 1)
626 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
628 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
630 local $Math::BigInt::accuracy = undef;
631 local $Math::BigInt::precision = undef;
632 if ($x->{sign} eq '-')
634 $x->{_n}->badd($x->{_d}); # -5/2 => -7/2
638 if ($x->{_n}->bacmp($x->{_d}) < 0)
641 $x->{_n} = $x->{_d} - $x->{_n};
646 $x->{_n}->bsub($x->{_d}); # 5/2 => 3/2
649 $x->bnorm()->round(@r);
654 # increment value (add 1)
655 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
657 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
659 local $Math::BigInt::accuracy = undef;
660 local $Math::BigInt::precision = undef;
661 if ($x->{sign} eq '-')
663 if ($x->{_n}->bacmp($x->{_d}) < 0)
665 # -1/3 ++ => 2/3 (overflow at 0)
666 $x->{_n} = $x->{_d} - $x->{_n};
671 $x->{_n}->bsub($x->{_d}); # -5/2 => -3/2
676 $x->{_n}->badd($x->{_d}); # 5/2 => 7/2
678 $x->bnorm()->round(@r);
681 ##############################################################################
682 # is_foo methods (the rest is inherited)
686 # return true if arg (BRAT or num_str) is an integer
687 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
689 return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't
690 $x->{_d}->is_one(); # x/y && y != 1 => no integer
696 # return true if arg (BRAT or num_str) is zero
697 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
699 return 1 if $x->{sign} eq '+' && $x->{_n}->is_zero();
705 # return true if arg (BRAT or num_str) is +1 or -1 if signis given
706 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
708 my $sign = $_[2] || ''; $sign = '+' if $sign ne '-';
710 if ($x->{sign} eq $sign && $x->{_n}->is_one() && $x->{_d}->is_one());
716 # return true if arg (BFLOAT or num_str) is odd or false if even
717 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
719 return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
720 ($x->{_d}->is_one() && $x->{_n}->is_odd()); # x/2 is not, but 3/1
726 # return true if arg (BINT or num_str) is even or false if odd
727 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
729 return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't
730 return 1 if ($x->{_d}->is_one() # x/3 is never
731 && $x->{_n}->is_even()); # but 4/1 is
735 ##############################################################################
736 # parts() and friends
740 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
742 return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
744 my $n = $x->{_n}->copy(); $n->{sign} = $x->{sign};
750 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
752 return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
758 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
760 return ($self->bnan(),$self->bnan()) if $x->{sign} eq 'NaN';
761 return ($self->binf(),$self->binf()) if $x->{sign} eq '+inf';
762 return ($self->binf('-'),$self->binf()) if $x->{sign} eq '-inf';
764 my $n = $x->{_n}->copy();
765 $n->{sign} = $x->{sign};
766 return ($n,$x->{_d}->copy());
771 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
773 return $nan unless $x->is_int();
774 $x->{_n}->length(); # length(-123/1) => length(123)
779 my ($self,$x,$n) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
781 return $nan unless $x->is_int();
782 $x->{_n}->digit($n); # digit(-123/1,2) => digit(123,2)
785 ##############################################################################
786 # special calc routines
790 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
792 return $x unless $x->{sign} =~ /^[+-]$/;
793 return $x if $x->{_d}->is_one(); # 22/1 => 22, 0/1 => 0
795 local $Math::BigInt::upgrade = undef;
796 local $Math::BigInt::accuracy = undef;
797 local $Math::BigInt::precision = undef;
798 $x->{_n}->bdiv($x->{_d}); # 22/7 => 3/1 w/ truncate
800 $x->{_n}->binc() if $x->{sign} eq '+'; # +22/7 => 4/1
801 $x->{sign} = '+' if $x->{_n}->is_zero(); # -0 => 0
807 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
809 return $x unless $x->{sign} =~ /^[+-]$/;
810 return $x if $x->{_d}->is_one(); # 22/1 => 22, 0/1 => 0
812 local $Math::BigInt::upgrade = undef;
813 local $Math::BigInt::accuracy = undef;
814 local $Math::BigInt::precision = undef;
815 $x->{_n}->bdiv($x->{_d}); # 22/7 => 3/1 w/ truncate
817 $x->{_n}->binc() if $x->{sign} eq '-'; # -22/7 => -4/1
823 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
825 # if $x is an integer
826 if (($x->{sign} eq '+') && ($x->{_d}->is_one()))
829 return $x->round(@r);
839 my ($self,$x,$y,@r) = (ref($_[0]),@_);
840 # objectify is costly, so avoid it
841 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
843 ($self,$x,$y,@r) = objectify(2,@_);
846 return $x if $x->{sign} =~ /^[+-]inf$/; # -inf/+inf ** x
847 return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
848 return $x->bone(@r) if $y->is_zero();
849 return $x->round(@r) if $x->is_one() || $y->is_one();
850 if ($x->{sign} eq '-' && $x->{_n}->is_one() && $x->{_d}->is_one())
852 # if $x == -1 and odd/even y => +1/-1
853 return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
854 # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
856 # 1 ** -y => 1 / (1 ** |y|)
857 # so do test for negative $y after above's clause
858 # return $x->bnan() if $y->{sign} eq '-';
859 return $x->round(@r) if $x->is_zero(); # 0**y => 0 (if not y <= 0)
861 # shortcut y/1 (and/or x/1)
862 if ($y->{_d}->is_one())
864 # shortcut for x/1 and y/1
865 if ($x->{_d}->is_one())
867 $x->{_n}->bpow($y->{_n}); # x/1 ** y/1 => (x ** y)/1
868 if ($y->{sign} eq '-')
870 # 0.2 ** -3 => 1/(0.2 ** 3)
871 ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n}); # swap
873 # correct sign; + ** + => +
874 if ($x->{sign} eq '-')
876 # - * - => +, - * - * - => -
877 $x->{sign} = '+' if $y->{_n}->is_even();
879 return $x->round(@r);
882 $x->{_n}->bpow($y->{_n}); # 5/2 ** y/1 => 5 ** y / 2 ** y
883 $x->{_d}->bpow($y->{_n});
884 if ($y->{sign} eq '-')
886 # 0.2 ** -3 => 1/(0.2 ** 3)
887 ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n}); # swap
889 # correct sign; + ** + => +
890 if ($x->{sign} eq '-')
892 # - * - => +, - * - * - => -
893 $x->{sign} = '+' if $y->{_n}->is_even();
895 return $x->round(@r);
898 # regular calculation (this is wrong for d/e ** f/g)
899 my $pow2 = $self->__one();
900 my $y1 = $MBI->new($y->{_n}/$y->{_d})->babs();
901 my $two = $MBI->new(2);
902 while (!$y1->is_one())
904 $pow2->bmul($x) if $y1->is_odd();
908 $x->bmul($pow2) unless $pow2->is_one();
909 # n ** -x => 1/n ** x
910 ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-';
911 $x->bnorm()->round(@r);
917 my ($self,$x,$y,@r) = (ref($_[0]),@_);
919 # objectify is costly, so avoid it
920 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
922 ($self,$x,$y,@r) = objectify(2,$class,@_);
926 return $x->bzero() if $x->is_one() && $y->{sign} eq '+';
929 return $x->bnan() if $x->is_zero() || $x->{sign} ne '+' || $y->{sign} ne '+';
931 if ($x->is_int() && $y->is_int())
933 return $self->new($x->as_number()->blog($y->as_number(),@r));
937 $x->_new_from_float( $x->_as_float()->blog(Math::BigFloat->new("$y"),@r) );
944 local $Math::BigFloat::upgrade = undef;
945 local $Math::BigFloat::accuracy = undef;
946 local $Math::BigFloat::precision = undef;
947 # 22/7 => 3.142857143..
948 Math::BigFloat->new($x->{_n})->bdiv($x->{_d}, $x->accuracy());
954 my ($self,$x,$y,@r) = (ref($_[0]),@_);
955 # objectify is costly, so avoid it
956 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
958 ($self,$x,$y,@r) = objectify(2,@_);
961 if ($x->is_int() && $y->is_int())
963 return $self->new($x->as_number()->broot($y->as_number(),@r));
967 $x->_new_from_float( $x->_as_float()->broot($y,@r) );
973 my ($self,$x,$y,$m,@r) = (ref($_[0]),@_);
974 # objectify is costly, so avoid it
975 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
977 ($self,$x,$y,$m,@r) = objectify(3,@_);
980 # $x or $y or $m are NaN or +-inf => NaN
982 if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/ ||
983 $m->{sign} !~ /^[+-]$/;
985 if ($x->is_int() && $y->is_int() && $m->is_int())
987 return $self->new($x->as_number()->bmodpow($y->as_number(),$m,@r));
990 warn ("bmodpow() not fully implemented");
997 my ($self,$x,$y,@r) = (ref($_[0]),@_);
998 # objectify is costly, so avoid it
999 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1001 ($self,$x,$y,@r) = objectify(2,@_);
1004 # $x or $y are NaN or +-inf => NaN
1006 if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/;
1008 if ($x->is_int() && $y->is_int())
1010 return $self->new($x->as_number()->bmodinv($y->as_number(),@r));
1013 warn ("bmodinv() not fully implemented");
1019 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
1021 return $x->bnan() if $x->{sign} !~ /^[+]/; # NaN, -inf or < 0
1022 return $x if $x->{sign} eq '+inf'; # sqrt(inf) == inf
1023 return $x->round(@r) if $x->is_zero() || $x->is_one();
1025 local $Math::BigFloat::upgrade = undef;
1026 local $Math::BigFloat::downgrade = undef;
1027 local $Math::BigFloat::precision = undef;
1028 local $Math::BigFloat::accuracy = undef;
1029 local $Math::BigInt::upgrade = undef;
1030 local $Math::BigInt::precision = undef;
1031 local $Math::BigInt::accuracy = undef;
1033 $x->{_d} = Math::BigFloat->new($x->{_d})->bsqrt();
1034 $x->{_n} = Math::BigFloat->new($x->{_n})->bsqrt();
1036 # if sqrt(D) was not integer
1037 if ($x->{_d}->{_es} ne '+')
1039 $x->{_n}->blsft($x->{_d}->exponent()->babs(),10); # 7.1/4.51 => 7.1/45.1
1040 $x->{_d} = $MBI->new($CALC->_str($x->{_d}->{_m})); # 7.1/45.1 => 71/45.1
1042 # if sqrt(N) was not integer
1043 if ($x->{_n}->{_es} ne '+')
1045 $x->{_d}->blsft($x->{_n}->exponent()->babs(),10); # 71/45.1 => 710/45.1
1046 $x->{_n} = $MBI->new($CALC->_str($x->{_n}->{_m})); # 710/45.1 => 710/451
1049 # convert parts to $MBI again
1050 $x->{_n} = $x->{_n}->as_number() unless $x->{_n}->isa($MBI);
1051 $x->{_d} = $x->{_d}->as_number() unless $x->{_d}->isa($MBI);
1052 $x->bnorm()->round(@r);
1057 my ($self,$x,$y,$b,@r) = objectify(3,@_);
1059 $b = 2 unless defined $b;
1060 $b = $self->new($b) unless ref ($b);
1061 $x->bmul( $b->copy()->bpow($y), @r);
1067 my ($self,$x,$y,$b,@r) = objectify(2,@_);
1069 $b = 2 unless defined $b;
1070 $b = $self->new($b) unless ref ($b);
1071 $x->bdiv( $b->copy()->bpow($y), @r);
1075 ##############################################################################
1093 ##############################################################################
1098 # compare two signed numbers
1101 my ($self,$x,$y) = (ref($_[0]),@_);
1102 # objectify is costly, so avoid it
1103 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1105 ($self,$x,$y) = objectify(2,@_);
1108 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1110 # handle +-inf and NaN
1111 return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1112 return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
1113 return +1 if $x->{sign} eq '+inf';
1114 return -1 if $x->{sign} eq '-inf';
1115 return -1 if $y->{sign} eq '+inf';
1118 # check sign for speed first
1119 return 1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # does also 0 <=> -y
1120 return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # does also -x <=> 0
1123 my $xz = $x->{_n}->is_zero();
1124 my $yz = $y->{_n}->is_zero();
1125 return 0 if $xz && $yz; # 0 <=> 0
1126 return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y
1127 return 1 if $yz && $x->{sign} eq '+'; # +x <=> 0
1129 my $t = $x->{_n} * $y->{_d}; $t->{sign} = $x->{sign};
1130 my $u = $y->{_n} * $x->{_d}; $u->{sign} = $y->{sign};
1136 # compare two numbers (as unsigned)
1139 my ($self,$x,$y) = (ref($_[0]),@_);
1140 # objectify is costly, so avoid it
1141 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1143 ($self,$x,$y) = objectify(2,$class,@_);
1146 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1148 # handle +-inf and NaN
1149 return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1150 return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
1151 return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
1155 my $t = $x->{_n} * $y->{_d};
1156 my $u = $y->{_n} * $x->{_d};
1160 ##############################################################################
1161 # output conversation
1165 # convert 17/8 => float (aka 2.125)
1166 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
1168 return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, NaN, etc
1171 return $x->{_n}->numify() if $x->{_d}->is_one();
1174 my $neg = 1; $neg = -1 if $x->{sign} ne '+';
1175 $neg * $x->{_n}->numify() / $x->{_d}->numify(); # return sign * N/D
1180 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1182 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf etc
1184 # need to disable these, otherwise bdiv() gives BigRat again
1185 local $Math::BigInt::upgrade = undef;
1186 local $Math::BigInt::accuracy = undef;
1187 local $Math::BigInt::precision = undef;
1188 my $t = $x->{_n}->copy()->bdiv($x->{_d}); # 22/7 => 3
1189 $t->{sign} = $x->{sign};
1195 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1197 return $x unless $x->is_int();
1199 my $s = $x->{sign}; $s = '' if $s eq '+';
1200 $s . $x->{_n}->as_bin();
1205 my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1207 return $x unless $x->is_int();
1209 my $s = $x->{sign}; $s = '' if $s eq '+';
1210 $s . $x->{_n}->as_hex();
1217 my $lib = ''; my @a;
1220 for ( my $i = 0; $i < $l ; $i++)
1222 # print "at $_[$i] (",$_[$i+1]||'undef',")\n";
1223 if ( $_[$i] eq ':constant' )
1225 # this rest causes overlord er load to step in
1226 # print "overload @_\n";
1227 overload::constant float => sub { $self->new(shift); };
1229 # elsif ($_[$i] eq 'upgrade')
1231 # # this causes upgrading
1232 # $upgrade = $_[$i+1]; # or undef to disable
1235 elsif ($_[$i] eq 'downgrade')
1237 # this causes downgrading
1238 $downgrade = $_[$i+1]; # or undef to disable
1241 elsif ($_[$i] eq 'lib')
1243 $lib = $_[$i+1] || ''; # default Calc
1246 elsif ($_[$i] eq 'with')
1248 $MBI = $_[$i+1] || 'Math::BigInt'; # default Math::BigInt
1256 # let use Math::BigInt lib => 'GMP'; use Math::BigRat; still work
1257 my $mbilib = eval { Math::BigInt->config()->{lib} };
1258 if ((defined $mbilib) && ($MBI eq 'Math::BigInt'))
1260 # MBI already loaded
1261 $MBI->import('lib',"$lib,$mbilib", 'objectify');
1265 # MBI not loaded, or not with "Math::BigInt"
1266 $lib .= ",$mbilib" if defined $mbilib;
1270 # Perl < 5.6.0 dies with "out of memory!" when eval() and ':constant' is
1271 # used in the same script, or eval inside import().
1272 my @parts = split /::/, $MBI; # Math::BigInt => Math BigInt
1273 my $file = pop @parts; $file .= '.pm'; # BigInt => BigInt.pm
1274 $file = File::Spec->catfile (@parts, $file);
1275 eval { require $file; $MBI->import( lib => '$lib', 'objectify' ); }
1279 my $rc = "use $MBI lib => '$lib', 'objectify';";
1285 require Carp; Carp::croak ("Couldn't load $MBI: $! $@");
1288 $CALC = Math::BigFloat->config()->{lib};
1290 # any non :constant stuff is handled by our parent, Exporter
1291 # even if @_ is empty, to give it a chance
1292 $self->SUPER::import(@a); # for subclasses
1293 $self->export_to_level(1,$self,@a); # need this, too
1302 Math::BigRat - arbitrarily big rational numbers
1308 my $x = Math::BigRat->new('3/7'); $x += '5/9';
1310 print $x->bstr(),"\n";
1313 my $y = Math::BigRat->new('inf');
1314 print "$y ", ($y->is_inf ? 'is' : 'is not') , " infinity\n";
1316 my $z = Math::BigRat->new(144); $z->bsqrt();
1320 Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
1321 for arbitrarily big rational numbers.
1325 Math with the numbers is done (by default) by a module called
1326 Math::BigInt::Calc. This is equivalent to saying:
1328 use Math::BigRat lib => 'Calc';
1330 You can change this by using:
1332 use Math::BigRat lib => 'BitVect';
1334 The following would first try to find Math::BigInt::Foo, then
1335 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
1337 use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
1339 Calc.pm uses as internal format an array of elements of some decimal base
1340 (usually 1e7, but this might be different for some systems) with the least
1341 significant digit first, while BitVect.pm uses a bit vector of base 2, most
1342 significant bit first. Other modules might use even different means of
1343 representing the numbers. See the respective module documentation for further
1346 Currently the following replacement libraries exist, search for them at CPAN:
1348 Math::BigInt::BitVect
1351 Math::BigInt::FastCalc
1355 Any methods not listed here are dervied from Math::BigFloat (or
1356 Math::BigInt), so make sure you check these two modules for further
1361 $x = Math::BigRat->new('1/3');
1363 Create a new Math::BigRat object. Input can come in various forms:
1365 $x = Math::BigRat->new(123); # scalars
1366 $x = Math::BigRat->new('inf'); # infinity
1367 $x = Math::BigRat->new('123.3'); # float
1368 $x = Math::BigRat->new('1/3'); # simple string
1369 $x = Math::BigRat->new('1 / 3'); # spaced
1370 $x = Math::BigRat->new('1 / 0.1'); # w/ floats
1371 $x = Math::BigRat->new(Math::BigInt->new(3)); # BigInt
1372 $x = Math::BigRat->new(Math::BigFloat->new('3.1')); # BigFloat
1373 $x = Math::BigRat->new(Math::BigInt::Lite->new('2')); # BigLite
1377 $n = $x->numerator();
1379 Returns a copy of the numerator (the part above the line) as signed BigInt.
1381 =head2 denominator()
1383 $d = $x->denominator();
1385 Returns a copy of the denominator (the part under the line) as positive BigInt.
1389 ($n,$d) = $x->parts();
1391 Return a list consisting of (signed) numerator and (unsigned) denominator as
1396 $x = Math::BigRat->new('13/7');
1397 print $x->as_number(),"\n"; # '1'
1399 Returns a copy of the object as BigInt trunced it to integer.
1405 Calculates the factorial of $x. For instance:
1407 print Math::BigRat->new('3/1')->bfac(),"\n"; # 1*2*3
1408 print Math::BigRat->new('5/1')->bfac(),"\n"; # 1*2*3*4*5
1410 Works currently only for integers.
1414 Is not yet implemented.
1416 =head2 bround()/round()/bfround()
1418 Are not yet implemented.
1423 my $x = Math::BigRat->new('7/4');
1424 my $y = Math::BigRat->new('4/3');
1427 Set $x to the remainder of the division of $x by $y.
1431 print "$x is 1\n" if $x->is_one();
1433 Return true if $x is exactly one, otherwise false.
1437 print "$x is 0\n" if $x->is_zero();
1439 Return true if $x is exactly zero, otherwise false.
1441 =head2 is_positive()
1443 print "$x is >= 0\n" if $x->is_positive();
1445 Return true if $x is positive (greater than or equal to zero), otherwise
1446 false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
1448 =head2 is_negative()
1450 print "$x is < 0\n" if $x->is_negative();
1452 Return true if $x is negative (smaller than zero), otherwise false. Please
1453 note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
1457 print "$x is an integer\n" if $x->is_int();
1459 Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
1460 false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
1464 print "$x is odd\n" if $x->is_odd();
1466 Return true if $x is odd, otherwise false.
1470 print "$x is even\n" if $x->is_even();
1472 Return true if $x is even, otherwise false.
1478 Set $x to the next bigger integer value (e.g. truncate the number to integer
1479 and then increment it by one).
1485 Truncate $x to an integer value.
1491 Calculate the square root of $x.
1497 print Dumper ( Math::BigRat->config() );
1498 print Math::BigRat->config()->{lib},"\n";
1500 Returns a hash containing the configuration, e.g. the version number, lib
1501 loaded etc. The following hash keys are currently filled in with the
1502 appropriate information.
1504 key RO/RW Description
1506 ============================================================
1507 lib RO Name of the Math library
1509 lib_version RO Version of 'lib'
1511 class RO The class of config you just called
1513 version RO version number of the class you used
1515 upgrade RW To which class numbers are upgraded
1517 downgrade RW To which class numbers are downgraded
1519 precision RW Global precision
1521 accuracy RW Global accuracy
1523 round_mode RW Global round mode
1525 div_scale RW Fallback acccuracy for div
1527 trap_nan RW Trap creation of NaN (undef = no)
1529 trap_inf RW Trap creation of +inf/-inf (undef = no)
1532 By passing a reference to a hash you may set the configuration values. This
1533 works only for values that a marked with a C<RW> above, anything else is
1538 Some things are not yet implemented, or only implemented half-way:
1542 =item inf handling (partial)
1544 =item NaN handling (partial)
1546 =item rounding (not implemented except for bceil/bfloor)
1548 =item $x ** $y where $y is not an integer
1550 =item bmod(), blog(), bmodinv() and bmodpow() (partial)
1556 This program is free software; you may redistribute it and/or modify it under
1557 the same terms as Perl itself.
1561 L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
1562 L<Math::BigInt::Pari> and L<Math::BigInt::GMP>.
1564 See L<http://search.cpan.org/search?dist=bignum> for a way to use
1567 The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
1568 may contain more documentation and examples as well as testcases.
1572 (C) by Tels L<http://bloodgate.com/> 2001, 2002, 2003, 2004.