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
21 use vars qw($VERSION @ISA $PACKAGE @EXPORT_OK $upgrade $downgrade
22 $accuracy $precision $round_mode $div_scale);
24 @ISA = qw(Exporter Math::BigFloat);
29 use overload; # inherit from Math::BigFloat
31 ##############################################################################
32 # global constants, flags and accessory
34 use constant MB_NEVER_ROUND => 0x0001;
36 $accuracy = $precision = undef;
43 my $class = 'Math::BigRat';
44 my $MBI = 'Math::BigInt';
48 return 0 if $_[1] =~ /^Math::Big(Int|Float)/; # we aren't
54 # turn a single float input into a rational (like '0.1')
57 return $self->bnan() if $f->is_nan();
58 return $self->binf('-inf') if $f->{sign} eq '-inf';
59 return $self->binf('+inf') if $f->{sign} eq '+inf';
61 #print "f $f caller", join(' ',caller()),"\n";
62 $self->{_n} = $f->{_m}->copy(); # mantissa
63 $self->{_d} = $MBI->bone();
64 $self->{sign} = $f->{sign}; $self->{_n}->{sign} = '+';
65 if ($f->{_e}->{sign} eq '-')
67 # something like Math::BigRat->new('0.1');
68 $self->{_d}->blsft($f->{_e}->copy()->babs(),10); # 1 / 1 => 1/10
72 # something like Math::BigRat->new('10');
74 $self->{_n}->blsft($f->{_e},10) unless $f->{_e}->is_zero();
81 # create a Math::BigRat
86 my $self = { }; bless $self,$class;
88 # input like (BigInt,BigInt) or (BigFloat,BigFloat) not handled yet
90 if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat')))
92 if ($n->isa('Math::BigFloat'))
94 return $self->_new_from_float($n)->bnorm();
96 if ($n->isa('Math::BigInt'))
98 $self->{_n} = $n->copy(); # "mantissa" = $n
99 $self->{_d} = $MBI->bone();
100 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
101 return $self->bnorm();
103 if ($n->isa('Math::BigInt::Lite'))
105 $self->{_n} = $MBI->new($$n); # "mantissa" = $n
106 $self->{_d} = $MBI->bone();
107 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
108 return $self->bnorm();
111 return $n->copy() if ref $n;
115 $self->{_n} = $MBI->bzero(); # undef => 0
116 $self->{_d} = $MBI->bone();
118 return $self->bnorm();
120 # string input with / delimiter
121 if ($n =~ /\s*\/\s*/)
123 return Math::BigRat->bnan() if $n =~ /\/.*\//; # 1/2/3 isn't valid
124 return Math::BigRat->bnan() if $n =~ /\/\s*$/; # 1/ isn't valid
125 ($n,$d) = split (/\//,$n);
126 # try as BigFloats first
127 if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/))
129 # one of them looks like a float
130 $self->_new_from_float(Math::BigFloat->new($n));
131 # now correct $self->{_n} due to $n
132 my $f = Math::BigFloat->new($d);
133 if ($f->{_e}->{sign} eq '-')
136 $self->{_n}->blsft($f->{_e}->copy()->babs(),10);
140 $self->{_d}->blsft($f->{_e},10); # 1 / 1 => 10/1
145 $self->{_n} = $MBI->new($n);
146 $self->{_d} = $MBI->new($d);
147 return $self->bnan() if $self->{_n}->is_nan() || $self->{_d}->is_nan();
148 # inf handling is missing here
150 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
151 # if $d is negative, flip sign
152 $self->{sign} =~ tr/+-/-+/ if $self->{_d}->{sign} eq '-';
153 $self->{_d}->{sign} = '+'; # normalize
155 return $self->bnorm();
158 # simple string input
159 if (($n =~ /[\.eE]/))
161 # work around bug in BigFloat that makes 1.1.2 valid
162 return $self->bnan() if $n =~ /\..*\./;
164 $self->_new_from_float(Math::BigFloat->new($n));
168 $self->{_n} = $MBI->new($n);
169 $self->{_d} = $MBI->bone();
170 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
171 return $self->bnan() if $self->{sign} eq 'NaN';
172 return $self->binf($self->{sign}) if $self->{sign} =~ /^[+-]inf$/;
177 ###############################################################################
181 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
183 if ($x->{sign} !~ /^[+-]$/) # inf, NaN etc
185 my $s = $x->{sign}; $s =~ s/^\+//; # +inf => inf
189 my $s = ''; $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3
191 return $s.$x->{_n}->bstr() if $x->{_d}->is_one();
192 return $s.$x->{_n}->bstr() . '/' . $x->{_d}->bstr();
197 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
199 if ($x->{sign} !~ /^[+-]$/) # inf, NaN etc
201 my $s = $x->{sign}; $s =~ s/^\+//; # +inf => inf
205 my $s = ''; $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3
206 return $x->{_n}->bstr() . '/' . $x->{_d}->bstr();
211 # reduce the number to the shortest form and remember this (so that we
212 # don't reduce again)
213 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
215 # both parts must be BigInt's
216 die ("n is not $MBI but (".ref($x->{_n}).')')
217 if ref($x->{_n}) ne $MBI;
218 die ("d is not $MBI but (".ref($x->{_d}).')')
219 if ref($x->{_d}) ne $MBI;
221 # this is to prevent automatically rounding when MBI's globals are set
222 $x->{_d}->{_f} = MB_NEVER_ROUND;
223 $x->{_n}->{_f} = MB_NEVER_ROUND;
224 # 'forget' that parts were rounded via MBI::bround() in MBF's bfround()
225 $x->{_d}->{_a} = undef; $x->{_n}->{_a} = undef;
226 $x->{_d}->{_p} = undef; $x->{_n}->{_p} = undef;
228 # no normalize for NaN, inf etc.
229 return $x if $x->{sign} !~ /^[+-]$/;
231 # normalize zeros to 0/1
232 if (($x->{sign} =~ /^[+-]$/) &&
233 ($x->{_n}->is_zero()))
235 $x->{sign} = '+'; # never -0
236 $x->{_d} = $MBI->bone() unless $x->{_d}->is_one();
240 return $x if $x->{_d}->is_one(); # no need to reduce
242 # reduce other numbers
243 # disable upgrade in BigInt, otherwise deep recursion
244 local $Math::BigInt::upgrade = undef;
245 my $gcd = $x->{_n}->bgcd($x->{_d});
249 $x->{_n}->bdiv($gcd);
250 $x->{_d}->bdiv($gcd);
255 ##############################################################################
260 # used by parent class bone() to initialize number to 1
262 $self->{_n} = $MBI->bzero();
263 $self->{_d} = $MBI->bzero();
268 # used by parent class bone() to initialize number to 1
270 $self->{_n} = $MBI->bzero();
271 $self->{_d} = $MBI->bzero();
276 # used by parent class bone() to initialize number to 1
278 $self->{_n} = $MBI->bone();
279 $self->{_d} = $MBI->bone();
284 # used by parent class bone() to initialize number to 1
286 $self->{_n} = $MBI->bzero();
287 $self->{_d} = $MBI->bone();
290 ##############################################################################
296 my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
298 $x = $self->new($x) unless $x->isa($self);
299 $y = $self->new($y) unless $y->isa($self);
301 return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
303 # 1 1 gcd(3,4) = 1 1*3 + 1*4 7
304 # - + - = --------- = --
307 my $gcd = $x->{_d}->bgcd($y->{_d});
309 my $aa = $x->{_d}->copy();
310 my $bb = $y->{_d}->copy();
313 $bb->bdiv($gcd); $aa->bdiv($gcd);
315 $x->{_n}->bmul($bb); $x->{_n}->{sign} = $x->{sign};
316 my $m = $y->{_n}->copy()->bmul($aa);
317 $m->{sign} = $y->{sign}; # 2/1 - 2/1
320 $x->{_d}->bmul($y->{_d});
323 $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
325 $x->bnorm()->round($a,$p,$r);
330 # subtract two rationals
331 my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
333 $x = $class->new($x) unless $x->isa($class);
334 $y = $class->new($y) unless $y->isa($class);
336 return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
339 # 1 1 gcd(3,4) = 1 1*3 + 1*4 7
340 # - + - = --------- = --
343 my $gcd = $x->{_d}->bgcd($y->{_d});
345 my $aa = $x->{_d}->copy();
346 my $bb = $y->{_d}->copy();
349 $bb->bdiv($gcd); $aa->bdiv($gcd);
351 $x->{_n}->bmul($bb); $x->{_n}->{sign} = $x->{sign};
352 my $m = $y->{_n}->copy()->bmul($aa);
353 $m->{sign} = $y->{sign}; # 2/1 - 2/1
356 $x->{_d}->bmul($y->{_d});
359 $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
361 $x->bnorm()->round($a,$p,$r);
366 # multiply two rationals
367 my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
369 $x = $class->new($x) unless $x->isa($class);
370 $y = $class->new($y) unless $y->isa($class);
372 return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
375 if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
377 return $x->bnan() if $x->is_zero() || $y->is_zero();
378 # result will always be +-inf:
379 # +inf * +/+inf => +inf, -inf * -/-inf => +inf
380 # +inf * -/-inf => -inf, -inf * +/+inf => -inf
381 return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
382 return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
383 return $x->binf('-');
386 # x== 0 # also: or y == 1 or y == -1
387 return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
389 # According to Knuth, this can be optimized by doingtwice gcd (for d and n)
390 # and reducing in one step)
395 $x->{_n}->bmul($y->{_n});
396 $x->{_d}->bmul($y->{_d});
399 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
401 $x->bnorm()->round($a,$p,$r);
406 # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
407 # (BRAT,BRAT) (quo,rem) or BRAT (only rem)
408 my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
410 $x = $class->new($x) unless $x->isa($class);
411 $y = $class->new($y) unless $y->isa($class);
413 return $self->_div_inf($x,$y)
414 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
416 # x== 0 # also: or y == 1 or y == -1
417 return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
419 # TODO: list context, upgrade
424 $x->{_n}->bmul($y->{_d});
425 $x->{_d}->bmul($y->{_n});
428 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
430 $x->bnorm()->round($a,$p,$r);
434 ##############################################################################
439 # decrement value (subtract 1)
440 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
442 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
444 if ($x->{sign} eq '-')
446 $x->{_n}->badd($x->{_d}); # -5/2 => -7/2
450 if ($x->{_n}->bacmp($x->{_d}) < 0)
453 $x->{_n} = $x->{_d} - $x->{_n};
458 $x->{_n}->bsub($x->{_d}); # 5/2 => 3/2
461 $x->bnorm()->round(@r);
463 #$x->bsub($self->bone())->round(@r);
468 # increment value (add 1)
469 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
471 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
473 if ($x->{sign} eq '-')
475 if ($x->{_n}->bacmp($x->{_d}) < 0)
477 # -1/3 ++ => 2/3 (overflow at 0)
478 $x->{_n} = $x->{_d} - $x->{_n};
483 $x->{_n}->bsub($x->{_d}); # -5/2 => -3/2
488 $x->{_n}->badd($x->{_d}); # 5/2 => 7/2
490 $x->bnorm()->round(@r);
492 #$x->badd($self->bone())->round(@r);
495 ##############################################################################
496 # is_foo methods (the rest is inherited)
500 # return true if arg (BRAT or num_str) is an integer
501 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
503 return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't
504 $x->{_d}->is_one(); # 1e-1 => no integer
510 # return true if arg (BRAT or num_str) is zero
511 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
513 return 1 if $x->{sign} eq '+' && $x->{_n}->is_zero();
519 # return true if arg (BRAT or num_str) is +1 or -1 if signis given
520 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
522 my $sign = shift || ''; $sign = '+' if $sign ne '-';
524 if ($x->{sign} eq $sign && $x->{_n}->is_one() && $x->{_d}->is_one());
530 # return true if arg (BFLOAT or num_str) is odd or false if even
531 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
533 return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
534 ($x->{_d}->is_one() && $x->{_n}->is_odd()); # x/2 is not, but 3/1
540 # return true if arg (BINT or num_str) is even or false if odd
541 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
543 return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't
544 return 1 if ($x->{_d}->is_one() # x/3 is never
545 && $x->{_n}->is_even()); # but 4/1 is
551 *objectify = \&Math::BigInt::objectify;
554 ##############################################################################
555 # parts() and friends
559 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
561 return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
563 my $n = $x->{_n}->copy(); $n->{sign} = $x->{sign};
569 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
571 return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
577 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
579 return ($self->bnan(),$self->bnan()) if $x->{sign} eq 'NaN';
580 return ($self->binf(),$self->binf()) if $x->{sign} eq '+inf';
581 return ($self->binf('-'),$self->binf()) if $x->{sign} eq '-inf';
583 my $n = $x->{_n}->copy();
584 $n->{sign} = $x->{sign};
585 return ($n,$x->{_d}->copy());
598 ##############################################################################
599 # special calc routines
603 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
605 return $x unless $x->{sign} =~ /^[+-]$/;
606 return $x if $x->{_d}->is_one(); # 22/1 => 22, 0/1 => 0
608 $x->{_n}->bdiv($x->{_d}); # 22/7 => 3/1 w/ truncate
610 $x->{_n}->binc() if $x->{sign} eq '+'; # +22/7 => 4/1
611 $x->{sign} = '+' if $x->{_n}->is_zero(); # -0 => 0
617 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
619 return $x unless $x->{sign} =~ /^[+-]$/;
620 return $x if $x->{_d}->is_one(); # 22/1 => 22, 0/1 => 0
622 $x->{_n}->bdiv($x->{_d}); # 22/7 => 3/1 w/ truncate
624 $x->{_n}->binc() if $x->{sign} eq '-'; # -22/7 => -4/1
630 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
632 if (($x->{sign} eq '+') && ($x->{_d}->is_one()))
635 return $x->round(@r);
642 my ($self,$x,$y,@r) = objectify(2,@_);
644 return $x if $x->{sign} =~ /^[+-]inf$/; # -inf/+inf ** x
645 return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
646 return $x->bone(@r) if $y->is_zero();
647 return $x->round(@r) if $x->is_one() || $y->is_one();
648 if ($x->{sign} eq '-' && $x->{_n}->is_one() && $x->{_d}->is_one())
650 # if $x == -1 and odd/even y => +1/-1
651 return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
652 # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
654 # 1 ** -y => 1 / (1 ** |y|)
655 # so do test for negative $y after above's clause
656 # return $x->bnan() if $y->{sign} eq '-';
657 return $x->round(@r) if $x->is_zero(); # 0**y => 0 (if not y <= 0)
659 # shortcut y/1 (and/or x/1)
660 if ($y->{_d}->is_one())
662 # shortcut for x/1 and y/1
663 if ($x->{_d}->is_one())
665 $x->{_n}->bpow($y->{_n}); # x/1 ** y/1 => (x ** y)/1
666 if ($y->{sign} eq '-')
668 # 0.2 ** -3 => 1/(0.2 ** 3)
669 ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n}); # swap
671 # correct sign; + ** + => +
672 if ($x->{sign} eq '-')
674 # - * - => +, - * - * - => -
675 $x->{sign} = '+' if $y->{_n}->is_even();
677 return $x->round(@r);
680 $x->{_n}->bpow($y->{_n}); # 5/2 ** y/1 => 5 ** y / 2 ** y
681 $x->{_d}->bpow($y->{_n});
682 if ($y->{sign} eq '-')
684 # 0.2 ** -3 => 1/(0.2 ** 3)
685 ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n}); # swap
687 # correct sign; + ** + => +
688 if ($x->{sign} eq '-')
690 # - * - => +, - * - * - => -
691 $x->{sign} = '+' if $y->{_n}->is_even();
693 return $x->round(@r);
696 # regular calculation (this is wrong for d/e ** f/g)
697 my $pow2 = $self->__one();
698 my $y1 = $MBI->new($y->{_n}/$y->{_d})->babs();
699 my $two = $MBI->new(2);
700 while (!$y1->is_one())
702 $pow2->bmul($x) if $y1->is_odd();
706 $x->bmul($pow2) unless $pow2->is_one();
707 # n ** -x => 1/n ** x
708 ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-';
715 return Math::BigRat->bnan();
720 my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
722 return $x->bnan() if $x->{sign} ne '+'; # inf, NaN, -1 etc
723 $x->{_d}->bsqrt($a,$p,$r);
724 $x->{_n}->bsqrt($a,$p,$r);
730 my ($self,$x,$y,$b,$a,$p,$r) = objectify(3,@_);
732 $x->bmul( $b->copy()->bpow($y), $a,$p,$r);
738 my ($self,$x,$y,$b,$a,$p,$r) = objectify(2,@_);
740 $x->bdiv( $b->copy()->bpow($y), $a,$p,$r);
744 ##############################################################################
762 ##############################################################################
767 my ($self,$x,$y) = objectify(2,@_);
769 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
771 # handle +-inf and NaN
772 return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
773 return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
774 return +1 if $x->{sign} eq '+inf';
775 return -1 if $x->{sign} eq '-inf';
776 return -1 if $y->{sign} eq '+inf';
779 # check sign for speed first
780 return 1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # does also 0 <=> -y
781 return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # does also -x <=> 0
784 my $xz = $x->{_n}->is_zero();
785 my $yz = $y->{_n}->is_zero();
786 return 0 if $xz && $yz; # 0 <=> 0
787 return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y
788 return 1 if $yz && $x->{sign} eq '+'; # +x <=> 0
790 my $t = $x->{_n} * $y->{_d}; $t->{sign} = $x->{sign};
791 my $u = $y->{_n} * $x->{_d}; $u->{sign} = $y->{sign};
797 my ($self,$x,$y) = objectify(2,@_);
799 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
801 # handle +-inf and NaN
802 return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
803 return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
804 return +1; # inf is always bigger
807 my $t = $x->{_n} * $y->{_d};
808 my $u = $y->{_n} * $x->{_d};
812 ##############################################################################
813 # output conversation
817 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
819 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf etc
820 my $t = $x->{_n}->copy()->bdiv($x->{_d}); # 22/7 => 3
821 $t->{sign} = $x->{sign};
830 for ( my $i = 0; $i < $l ; $i++)
832 # print "at $_[$i] (",$_[$i+1]||'undef',")\n";
833 if ( $_[$i] eq ':constant' )
835 # this rest causes overlord er load to step in
836 # print "overload @_\n";
837 overload::constant float => sub { $self->new(shift); };
839 # elsif ($_[$i] eq 'upgrade')
841 # # this causes upgrading
842 # $upgrade = $_[$i+1]; # or undef to disable
845 elsif ($_[$i] eq 'downgrade')
847 # this causes downgrading
848 $downgrade = $_[$i+1]; # or undef to disable
851 elsif ($_[$i] eq 'lib')
853 $lib = $_[$i+1] || ''; # default Calc
856 elsif ($_[$i] eq 'with')
858 $MBI = $_[$i+1] || 'Math::BigInt'; # default Math::BigInt
866 # let use Math::BigInt lib => 'GMP'; use Math::BigFloat; still work
867 my $mbilib = eval { Math::BigInt->config()->{lib} };
868 if ((defined $mbilib) && ($MBI eq 'Math::BigInt'))
871 $MBI->import('lib',"$lib,$mbilib", 'objectify');
875 # MBI not loaded, or not with "Math::BigInt"
876 $lib .= ",$mbilib" if defined $mbilib;
880 # Perl < 5.6.0 dies with "out of memory!" when eval() and ':constant' is
881 # used in the same script, or eval inside import().
882 my @parts = split /::/, $MBI; # Math::BigInt => Math BigInt
883 my $file = pop @parts; $file .= '.pm'; # BigInt => BigInt.pm
884 $file = File::Spec->catfile (@parts, $file);
885 eval { require $file; $MBI->import( lib => '$lib', 'objectify' ); }
889 my $rc = "use $MBI lib => '$lib', 'objectify';";
893 die ("Couldn't load $MBI: $! $@") if $@;
895 # any non :constant stuff is handled by our parent, Exporter
896 # even if @_ is empty, to give it a chance
897 $self->SUPER::import(@a); # for subclasses
898 $self->export_to_level(1,$self,@a); # need this, too
907 Math::BigRat - arbitrarily big rationals
913 $x = Math::BigRat->new('3/7');
915 print $x->bstr(),"\n";
919 This is just a placeholder until the real thing is up and running. Watch this
924 Math with the numbers is done (by default) by a module called
925 Math::BigInt::Calc. This is equivalent to saying:
927 use Math::BigRat lib => 'Calc';
929 You can change this by using:
931 use Math::BigRat lib => 'BitVect';
933 The following would first try to find Math::BigInt::Foo, then
934 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
936 use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
938 Calc.pm uses as internal format an array of elements of some decimal base
939 (usually 1e7, but this might be differen for some systems) with the least
940 significant digit first, while BitVect.pm uses a bit vector of base 2, most
941 significant bit first. Other modules might use even different means of
942 representing the numbers. See the respective module documentation for further
947 Any method not listed here is dervied from Math::BigFloat (or
948 Math::BigInt), so make sure you check these two modules for further
953 $x = Math::BigRat->new('1/3');
955 Create a new Math::BigRat object. Input can come in various forms:
957 $x = Math::BigRat->new('1/3'); # simple string
958 $x = Math::BigRat->new('1 / 3'); # spaced
959 $x = Math::BigRat->new('1 / 0.1'); # w/ floats
960 $x = Math::BigRat->new(Math::BigInt->new(3)); # BigInt
961 $x = Math::BigRat->new(Math::BigFloat->new('3.1')); # BigFloat
962 $x = Math::BigRat->new(Math::BigInt::Lite->new('2')); # BigLite
966 $n = $x->numerator();
968 Returns a copy of the numerator (the part above the line) as signed BigInt.
972 $d = $x->denominator();
974 Returns a copy of the denominator (the part under the line) as positive BigInt.
978 ($n,$d) = $x->parts();
980 Return a list consisting of (signed) numerator and (unsigned) denominator as
985 Returns a copy of the object as BigInt by truncating it to integer.
991 Calculates the factorial of $x. For instance:
993 print Math::BigRat->new('3/1')->bfac(),"\n"; # 1*2*3
994 print Math::BigRat->new('5/1')->bfac(),"\n"; # 1*2*3*4*5
996 Only works for integers for now.
1000 Is not yet implemented.
1002 =head2 bround()/round()/bfround()
1004 Are not yet implemented.
1009 Some things are not yet implemented, or only implemented half-way.
1013 This program is free software; you may redistribute it and/or modify it under
1014 the same terms as Perl itself.
1018 L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
1019 L<Math::BigInt::Pari> and L<Math::BigInt::GMP>.
1022 L<http://search.cpan.org/search?mode=module&query=Math%3A%3ABigRat> may
1023 contain more documentation and examples as well as testcases.
1027 (C) by Tels L<http://bloodgate.com/> 2001-2002.