summaryrefslogtreecommitdiff
path: root/systems/texlive/tlnet/tlpkg/tlperl/lib/Math/BigRat.pm
diff options
context:
space:
mode:
Diffstat (limited to 'systems/texlive/tlnet/tlpkg/tlperl/lib/Math/BigRat.pm')
-rw-r--r--systems/texlive/tlnet/tlpkg/tlperl/lib/Math/BigRat.pm902
1 files changed, 644 insertions, 258 deletions
diff --git a/systems/texlive/tlnet/tlpkg/tlperl/lib/Math/BigRat.pm b/systems/texlive/tlnet/tlpkg/tlperl/lib/Math/BigRat.pm
index e3d172836c..0d0f246795 100644
--- a/systems/texlive/tlnet/tlpkg/tlperl/lib/Math/BigRat.pm
+++ b/systems/texlive/tlnet/tlpkg/tlperl/lib/Math/BigRat.pm
@@ -16,11 +16,12 @@ use 5.006;
use strict;
use warnings;
-use Carp qw< carp croak >;
+use Carp qw< carp croak >;
+use Scalar::Util qw< blessed >;
-use Math::BigFloat 1.999718;
+use Math::BigFloat ();
-our $VERSION = '0.2614';
+our $VERSION = '0.2624';
our @ISA = qw(Math::BigFloat);
@@ -199,12 +200,6 @@ use overload
BEGIN {
*objectify = \&Math::BigInt::objectify; # inherit this from BigInt
*AUTOLOAD = \&Math::BigFloat::AUTOLOAD; # can't inherit AUTOLOAD
- # We inherit these from BigFloat because currently it is not possible that
- # Math::BigFloat has a different $LIB variable than we, because
- # Math::BigFloat also uses Math::BigInt::config->('lib') (there is always
- # only one library loaded)
- *_e_add = \&Math::BigFloat::_e_add;
- *_e_sub = \&Math::BigFloat::_e_sub;
*as_number = \&as_int;
*is_pos = \&is_positive;
*is_neg = \&is_negative;
@@ -305,20 +300,32 @@ sub new {
unless (defined $d) {
#return $n -> copy($n) if $n -> isa('Math::BigRat');
- return $class -> copy($n) if $n -> isa('Math::BigRat');
- return $class -> bnan() if $n -> is_nan();
- return $class -> binf($n -> sign()) if $n -> is_inf();
+ if ($n -> isa('Math::BigRat')) {
+ return $downgrade -> new($n)
+ if defined($downgrade) && $n -> is_int();
+ return $class -> copy($n);
+ }
+
+ if ($n -> is_nan()) {
+ return $class -> bnan();
+ }
+
+ if ($n -> is_inf()) {
+ return $class -> binf($n -> sign());
+ }
if ($n -> isa('Math::BigInt')) {
- $self -> {_n} = $LIB -> _new($n -> copy() -> babs() -> bstr());
+ $self -> {_n} = $LIB -> _new($n -> copy() -> babs(undef, undef)
+ -> bstr());
$self -> {_d} = $LIB -> _one();
$self -> {sign} = $n -> sign();
+ return $downgrade -> new($n) if defined $downgrade;
return $self;
}
if ($n -> isa('Math::BigFloat')) {
- my $m = $n -> mantissa() -> babs();
- my $e = $n -> exponent();
+ my $m = $n -> mantissa(undef, undef) -> babs(undef, undef);
+ my $e = $n -> exponent(undef, undef);
$self -> {_n} = $LIB -> _new($m -> bstr());
$self -> {_d} = $LIB -> _one();
@@ -329,7 +336,8 @@ sub new {
$self -> {_d} = $LIB -> _lsft($self -> {_d},
$LIB -> _new(-$e -> bstr()), 10);
- my $gcd = $LIB -> _gcd($LIB -> _copy($self -> {_n}), $self -> {_d});
+ my $gcd = $LIB -> _gcd($LIB -> _copy($self -> {_n}),
+ $self -> {_d});
if (!$LIB -> _is_one($gcd)) {
$self -> {_n} = $LIB -> _div($self->{_n}, $gcd);
$self -> {_d} = $LIB -> _div($self->{_d}, $gcd);
@@ -337,6 +345,8 @@ sub new {
}
$self -> {sign} = $n -> sign();
+ return $downgrade -> new($n, undef, undef)
+ if defined($downgrade) && $n -> is_int();
return $self;
}
@@ -353,19 +363,30 @@ sub new {
# At this point both $n and $d are objects.
- return $class -> bnan() if $n -> is_nan() || $d -> is_nan();
+ if ($n -> is_nan() || $d -> is_nan()) {
+ return $class -> bnan();
+ }
# At this point neither $n nor $d is a NaN.
if ($n -> is_zero()) {
- return $class -> bnan() if $d -> is_zero(); # 0/0 = NaN
+ if ($d -> is_zero()) { # 0/0 = NaN
+ return $class -> bnan();
+ }
return $class -> bzero();
}
- return $class -> binf($d -> sign()) if $d -> is_zero();
+ if ($d -> is_zero()) {
+ return $class -> binf($d -> sign());
+ }
# At this point, neither $n nor $d is a NaN or a zero.
+ # Copy them now before manipulating them.
+
+ $n = $n -> copy();
+ $d = $d -> copy();
+
if ($d < 0) { # make sure denominator is positive
$n -> bneg();
$d -> bneg();
@@ -411,6 +432,8 @@ sub new {
$self -> {_d} = $LIB -> _mul($LIB -> _div($LIB -> _copy($q), $gcd_sq),
$LIB -> _div($LIB -> _copy($r), $gcd_pr));
+ return $downgrade -> new($n->bstr())
+ if defined($downgrade) && $self -> is_int();
return $self; # no need for $self -> bnorm() here
}
@@ -516,6 +539,8 @@ sub new {
}
}
+ return $downgrade -> new($self -> bstr())
+ if defined($downgrade) && $self -> is_int();
return $self;
}
@@ -553,6 +578,8 @@ sub bnan {
croak ("Tried to set a variable to NaN in $class->bnan()");
}
+ return $downgrade -> bnan() if defined $downgrade;
+
$self -> {sign} = $nan;
$self -> {_n} = $LIB -> _zero();
$self -> {_d} = $LIB -> _one();
@@ -577,6 +604,8 @@ sub binf {
croak ("Tried to set a variable to +-inf in $class->binf()");
}
+ return $downgrade -> binf($sign) if defined $downgrade;
+
$self -> {sign} = $sign;
$self -> {_n} = $LIB -> _zero();
$self -> {_d} = $LIB -> _one();
@@ -592,11 +621,12 @@ sub bone {
my $selfref = ref $self;
my $class = $selfref || $self;
- $self = bless {}, $class unless $selfref;
-
my $sign = shift();
$sign = '+' unless defined($sign) && $sign eq '-';
+ return $downgrade -> bone($sign) if defined $downgrade;
+
+ $self = bless {}, $class unless $selfref;
$self -> {sign} = $sign;
$self -> {_n} = $LIB -> _one();
$self -> {_d} = $LIB -> _one();
@@ -612,8 +642,9 @@ sub bzero {
my $selfref = ref $self;
my $class = $selfref || $self;
- $self = bless {}, $class unless $selfref;
+ return $downgrade -> bzero() if defined $downgrade;
+ $self = bless {}, $class unless $selfref;
$self -> {sign} = '+';
$self -> {_n} = $LIB -> _zero();
$self -> {_d} = $LIB -> _one();
@@ -644,36 +675,86 @@ sub config {
$cfg;
}
-##############################################################################
+###############################################################################
+# String conversion methods
+###############################################################################
sub bstr {
- my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
+ my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
+
+ carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
+
+ # Inf and NaN
- if ($x->{sign} !~ /^[+-]$/) { # inf, NaN etc
- my $s = $x->{sign};
- $s =~ s/^\+//; # +inf => inf
- return $s;
+ if ($x->{sign} ne '+' && $x->{sign} ne '-') {
+ return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
+ return 'inf'; # +inf
}
+ # Upgrade?
+
+ return $upgrade -> bstr($x, @r)
+ if defined($upgrade) && !$x -> isa($class);
+
+ # Finite number
+
my $s = '';
$s = $x->{sign} if $x->{sign} ne '+'; # '+3/2' => '3/2'
- return $s . $LIB->_str($x->{_n}) if $LIB->_is_one($x->{_d});
- $s . $LIB->_str($x->{_n}) . '/' . $LIB->_str($x->{_d});
+ my $str = $x->{sign} eq '-' ? '-' : '';
+ $str .= $LIB->_str($x->{_n});
+ $str .= '/' . $LIB->_str($x->{_d}) unless $LIB -> _is_one($x->{_d});
+ return $str;
}
sub bsstr {
- my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
+ my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
+
+ carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
- if ($x->{sign} !~ /^[+-]$/) { # inf, NaN etc
- my $s = $x->{sign};
- $s =~ s/^\+//; # +inf => inf
- return $s;
+ # Inf and NaN
+
+ if ($x->{sign} ne '+' && $x->{sign} ne '-') {
+ return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
+ return 'inf'; # +inf
}
- my $s = '';
- $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3
- $s . $LIB->_str($x->{_n}) . '/' . $LIB->_str($x->{_d});
+ # Upgrade?
+
+ return $upgrade -> bsstr($x, @r)
+ if defined($upgrade) && !$x -> isa($class);
+
+ # Finite number
+
+ my $str = $x->{sign} eq '-' ? '-' : '';
+ $str .= $LIB->_str($x->{_n});
+ $str .= '/' . $LIB->_str($x->{_d}) unless $LIB -> _is_one($x->{_d});
+ return $str;
+}
+
+sub bfstr {
+ my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
+
+ carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
+
+ # Inf and NaN
+
+ if ($x->{sign} ne '+' && $x->{sign} ne '-') {
+ return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
+ return 'inf'; # +inf
+ }
+
+ # Upgrade?
+
+ return $upgrade -> bfstr($x, @r)
+ if defined($upgrade) && !$x -> isa($class);
+
+ # Finite number
+
+ my $str = $x->{sign} eq '-' ? '-' : '';
+ $str .= $LIB->_str($x->{_n});
+ $str .= '/' . $LIB->_str($x->{_d}) unless $LIB -> _is_one($x->{_d});
+ return $str;
}
sub bnorm {
@@ -689,16 +770,24 @@ sub bnorm {
}
# no normalize for NaN, inf etc.
- return $x if $x->{sign} !~ /^[+-]$/;
+ if ($x->{sign} !~ /^[+-]$/) {
+ return $downgrade -> new($x) if defined $downgrade;
+ return $x;
+ }
# normalize zeros to 0/1
if ($LIB->_is_zero($x->{_n})) {
+ return $downgrade -> bzero() if defined($downgrade);
$x->{sign} = '+'; # never leave a -0
$x->{_d} = $LIB->_one() unless $LIB->_is_one($x->{_d});
return $x;
}
- return $x if $LIB->_is_one($x->{_d}); # no need to reduce
+ # n/1
+ if ($LIB->_is_one($x->{_d})) {
+ return $downgrade -> new($x) if defined($downgrade);
+ return $x; # no need to reduce
+ }
# Compute the GCD.
my $gcd = $LIB->_gcd($LIB->_copy($x->{_n}), $x->{_d});
@@ -723,56 +812,10 @@ sub bneg {
# for +0 do not negate (to have always normalized +0). Does nothing for 'NaN'
$x->{sign} =~ tr/+-/-+/
unless ($x->{sign} eq '+' && $LIB->_is_zero($x->{_n}));
- $x;
-}
-
-##############################################################################
-# special values
-
-sub _bnan {
- # used by parent class bnan() to initialize number to NaN
- my $self = shift;
-
- if ($_trap_nan) {
- my $class = ref($self);
- # "$self" below will stringify the object, this blows up if $self is a
- # partial object (happens under trap_nan), so fix it beforehand
- $self->{_d} = $LIB->_zero() unless defined $self->{_d};
- $self->{_n} = $LIB->_zero() unless defined $self->{_n};
- croak ("Tried to set $self to NaN in $class\::_bnan()");
- }
- $self->{_n} = $LIB->_zero();
- $self->{_d} = $LIB->_zero();
-}
-
-sub _binf {
- # used by parent class bone() to initialize number to +inf/-inf
- my $self = shift;
-
- if ($_trap_inf) {
- my $class = ref($self);
- # "$self" below will stringify the object, this blows up if $self is a
- # partial object (happens under trap_nan), so fix it beforehand
- $self->{_d} = $LIB->_zero() unless defined $self->{_d};
- $self->{_n} = $LIB->_zero() unless defined $self->{_n};
- croak ("Tried to set $self to inf in $class\::_binf()");
- }
- $self->{_n} = $LIB->_zero();
- $self->{_d} = $LIB->_zero();
-}
-
-sub _bone {
- # used by parent class bone() to initialize number to +1/-1
- my $self = shift;
- $self->{_n} = $LIB->_one();
- $self->{_d} = $LIB->_one();
-}
-sub _bzero {
- # used by parent class bzero() to initialize number to 0
- my $self = shift;
- $self->{_n} = $LIB->_zero();
- $self->{_d} = $LIB->_one();
+ return $downgrade -> new($x)
+ if defined($downgrade) && $LIB -> _is_one($x->{_d});
+ $x;
}
##############################################################################
@@ -788,12 +831,21 @@ sub badd {
($class, $x, $y, @r) = objectify(2, @_);
}
- # +inf + +inf => +inf, -inf + -inf => -inf
- return $x->binf(substr($x->{sign}, 0, 1))
- if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
-
- # +inf + -inf or -inf + +inf => NaN
- return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
+ unless ($x -> is_finite() && $y -> is_finite()) {
+ if ($x -> is_nan() || $y -> is_nan()) {
+ return $x -> bnan(@r);
+ } elsif ($x -> is_inf("+")) {
+ return $x -> bnan(@r) if $y -> is_inf("-");
+ return $x -> binf("+", @r);
+ } elsif ($x -> is_inf("-")) {
+ return $x -> bnan(@r) if $y -> is_inf("+");
+ return $x -> binf("-", @r);
+ } elsif ($y -> is_inf("+")) {
+ return $x -> binf("+", @r);
+ } elsif ($y -> is_inf("-")) {
+ return $x -> binf("-", @r);
+ }
+ }
# 1 1 gcd(3, 4) = 1 1*3 + 1*4 7
# - + - = --------- = --
@@ -813,7 +865,7 @@ sub badd {
my $m = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
# 5 * 3 + 7 * 4
- ($x->{_n}, $x->{sign}) = _e_add($x->{_n}, $m, $x->{sign}, $y->{sign});
+ ($x->{_n}, $x->{sign}) = $LIB -> _sadd($x->{_n}, $x->{sign}, $m, $y->{sign});
# 4 * 3
$x->{_d} = $LIB->_mul($x->{_d}, $y->{_d});
@@ -834,12 +886,12 @@ sub bsub {
# flip sign of $x, call badd(), then flip sign of result
$x->{sign} =~ tr/+-/-+/
- unless $x->{sign} eq '+' && $LIB->_is_zero($x->{_n}); # not -0
- $x->badd($y, @r); # does norm and round
+ unless $x->{sign} eq '+' && $x -> is_zero(); # not -0
+ $x = $x->badd($y, @r); # does norm and round
$x->{sign} =~ tr/+-/-+/
- unless $x->{sign} eq '+' && $LIB->_is_zero($x->{_n}); # not -0
+ unless $x->{sign} eq '+' && $x -> is_zero(); # not -0
- $x;
+ $x->bnorm();
}
sub bmul {
@@ -866,10 +918,13 @@ sub bmul {
}
# x == 0 # also: or y == 1 or y == -1
- return wantarray ? ($x, $class->bzero()) : $x if $x -> is_zero();
+ if ($x -> is_zero()) {
+ $x = $downgrade -> bzero($x) if defined $downgrade;
+ return wantarray ? ($x, $class->bzero()) : $x;
+ }
if ($y -> is_zero()) {
- $x -> bzero();
+ $x = defined($downgrade) ? $downgrade -> bzero($x) : $x -> bzero();
return wantarray ? ($x, $class->bzero()) : $x;
}
@@ -893,7 +948,7 @@ sub bmul {
# compute new sign
$x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
- $x->round(@r);
+ $x->bnorm()->round(@r);
}
sub bdiv {
@@ -916,7 +971,15 @@ sub bdiv {
# method.
if ($x -> is_nan() || $y -> is_nan()) {
- return $wantarray ? ($x -> bnan(), $class -> bnan()) : $x -> bnan();
+ if ($wantarray) {
+ return $downgrade -> bnan(), $downgrade -> bnan()
+ if defined($downgrade);
+ return $x -> bnan(), $class -> bnan();
+ } else {
+ return $downgrade -> bnan()
+ if defined($downgrade);
+ return $x -> bnan();
+ }
}
# Divide by zero and modulo zero. This is handled the same way as in
@@ -933,6 +996,11 @@ sub bdiv {
} else {
$quo = $x -> binf($x -> {sign});
}
+
+ $quo = $downgrade -> new($quo)
+ if defined($downgrade) && $quo -> is_int();
+ $rem = $downgrade -> new($rem)
+ if $wantarray && defined($downgrade) && $rem -> is_int();
return $wantarray ? ($quo, $rem) : $quo;
}
@@ -949,6 +1017,11 @@ sub bdiv {
my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
$quo = $x -> binf($sign);
}
+
+ $quo = $downgrade -> new($quo)
+ if defined($downgrade) && $quo -> is_int();
+ $rem = $downgrade -> new($rem)
+ if $wantarray && defined($downgrade) && $rem -> is_int();
return $wantarray ? ($quo, $rem) : $quo;
}
@@ -966,12 +1039,18 @@ sub bdiv {
$rem = $class -> binf($y -> {sign});
$quo = $x -> bone('-');
}
+ $quo = $downgrade -> new($quo)
+ if defined($downgrade) && $quo -> is_int();
+ $rem = $downgrade -> new($rem)
+ if defined($downgrade) && $rem -> is_int();
return ($quo, $rem);
} else {
if ($y -> is_inf()) {
if ($x -> is_nan() || $x -> is_inf()) {
+ return $downgrade -> bnan() if defined $downgrade;
return $x -> bnan();
} else {
+ return $downgrade -> bzero() if defined $downgrade;
return $x -> bzero();
}
}
@@ -982,7 +1061,11 @@ sub bdiv {
# the denominator (divisor) is non-zero.
# x == 0?
- return wantarray ? ($x, $class->bzero()) : $x if $x->is_zero();
+ if ($x->is_zero()) {
+ return $wantarray ? ($downgrade -> bzero(), $downgrade -> bzero())
+ : $downgrade -> bzero() if defined $downgrade;
+ return $wantarray ? ($x, $class->bzero()) : $x;
+ }
# XXX TODO: list context, upgrade
# According to Knuth, this can be optimized by doing gcd twice (for d and n)
@@ -1001,13 +1084,14 @@ sub bdiv {
$x -> bnorm();
if (wantarray) {
my $rem = $x -> copy();
- $x -> bfloor();
- $x -> round(@r);
- $rem -> bsub($x -> copy()) -> bmul($y);
+ $x = $x -> bfloor();
+ $x = $x -> round(@r);
+ $rem = $rem -> bsub($x -> copy()) -> bmul($y);
+ $x = $downgrade -> new($x) if defined($downgrade) && $x -> is_int();
+ $rem = $downgrade -> new($rem) if defined($downgrade) && $rem -> is_int();
return $x, $rem;
} else {
- $x -> round(@r);
- return $x;
+ return $x -> round(@r);
}
}
@@ -1033,6 +1117,7 @@ sub bmod {
# Modulo zero. This is handled the same way as in Math::BigInt -> bmod().
if ($y -> is_zero()) {
+ return $downgrade -> bzero() if defined $downgrade;
return $x;
}
@@ -1048,8 +1133,10 @@ sub bmod {
if ($y -> is_inf()) {
if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
+ return $downgrade -> new($x) if defined($downgrade) && $x -> is_int();
return $x;
} else {
+ return $downgrade -> binf($y -> sign()) if defined($downgrade);
return $x -> binf($y -> sign());
}
}
@@ -1057,7 +1144,10 @@ sub bmod {
# At this point, both the numerator and denominator are finite numbers, and
# the denominator (divisor) is non-zero.
- return $x if $x->is_zero(); # 0 / 7 = 0, mod 0
+ if ($x->is_zero()) { # 0 / 7 = 0, mod 0
+ return $downgrade -> bzero() if defined $downgrade;
+ return $x;
+ }
# Compute $x - $y * floor($x/$y). This can probably be optimized by working
# on a lower level.
@@ -1073,7 +1163,10 @@ sub bdec {
# decrement value (subtract 1)
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
- return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
+ if ($x->{sign} !~ /^[+-]$/) { # NaN, inf, -inf
+ return $downgrade -> new($x) if defined $downgrade;
+ return $x;
+ }
if ($x->{sign} eq '-') {
$x->{_n} = $LIB->_add($x->{_n}, $x->{_d}); # -5/2 => -7/2
@@ -1094,7 +1187,10 @@ sub binc {
# increment value (add 1)
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
- return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
+ if ($x->{sign} !~ /^[+-]$/) { # NaN, inf, -inf
+ return $downgrade -> new($x) if defined $downgrade;
+ return $x;
+ }
if ($x->{sign} eq '-') {
if ($LIB->_acmp($x->{_n}, $x->{_d}) < 0) {
@@ -1110,6 +1206,20 @@ sub binc {
$x->bnorm()->round(@r);
}
+sub binv {
+ my $x = shift;
+ my @r = @_;
+
+ return $x if $x->modify('binv');
+
+ return $x if $x -> is_nan();
+ return $x -> bzero() if $x -> is_inf();
+ return $x -> binf("+") if $x -> is_zero();
+
+ ($x -> {_n}, $x -> {_d}) = ($x -> {_d}, $x -> {_n});
+ $x -> round(@r);
+}
+
##############################################################################
# is_foo methods (the rest is inherited)
@@ -1201,6 +1311,53 @@ sub parts {
($n, $d);
}
+sub dparts {
+ my $x = shift;
+ my $class = ref $x;
+
+ croak("dparts() is an instance method") unless $class;
+
+ if ($x -> is_nan()) {
+ return $class -> bnan(), $class -> bnan() if wantarray;
+ return $class -> bnan();
+ }
+
+ if ($x -> is_inf()) {
+ return $class -> binf($x -> sign()), $class -> bzero() if wantarray;
+ return $class -> binf($x -> sign());
+ }
+
+ # 355/113 => 3 + 16/113
+
+ my ($q, $r) = $LIB -> _div($LIB -> _copy($x -> {_n}), $x -> {_d});
+
+ my $int = Math::BigRat -> new($x -> {sign} . $LIB -> _str($q));
+ return $int unless wantarray;
+
+ my $frc = Math::BigRat -> new($x -> {sign} . $LIB -> _str($r),
+ $LIB -> _str($x -> {_d}));
+
+ return $int, $frc;
+}
+
+sub fparts {
+ my $x = shift;
+ my $class = ref $x;
+
+ croak("fparts() is an instance method") unless $class;
+
+ return ($class -> bnan(),
+ $class -> bnan()) if $x -> is_nan();
+
+ my $numer = $x -> copy();
+ my $denom = $class -> bzero();
+
+ $denom -> {_n} = $numer -> {_d};
+ $numer -> {_d} = $LIB -> _one();
+
+ return ($numer, $denom);
+}
+
sub length {
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
@@ -1221,37 +1378,52 @@ sub digit {
sub bceil {
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
- return $x if ($x->{sign} !~ /^[+-]$/ || # not for NaN, inf
- $LIB->_is_one($x->{_d})); # 22/1 => 22, 0/1 => 0
+ if ($x->{sign} !~ /^[+-]$/ || # NaN or inf or
+ $LIB->_is_one($x->{_d})) # integer
+ {
+ return $downgrade -> new($x) if defined $downgrade;
+ return $x;
+ }
$x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
$x->{_d} = $LIB->_one(); # d => 1
$x->{_n} = $LIB->_inc($x->{_n}) if $x->{sign} eq '+'; # +22/7 => 4/1
$x->{sign} = '+' if $x->{sign} eq '-' && $LIB->_is_zero($x->{_n}); # -0 => 0
+ return $downgrade -> new($x) if defined $downgrade;
$x;
}
sub bfloor {
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
- return $x if ($x->{sign} !~ /^[+-]$/ || # not for NaN, inf
- $LIB->_is_one($x->{_d})); # 22/1 => 22, 0/1 => 0
+ if ($x->{sign} !~ /^[+-]$/ || # NaN or inf or
+ $LIB->_is_one($x->{_d})) # integer
+ {
+ return $downgrade -> new($x) if defined $downgrade;
+ return $x;
+ }
$x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
$x->{_d} = $LIB->_one(); # d => 1
$x->{_n} = $LIB->_inc($x->{_n}) if $x->{sign} eq '-'; # -22/7 => -4/1
+ return $downgrade -> new($x) if defined $downgrade;
$x;
}
sub bint {
- my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
+ my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
- return $x if ($x->{sign} !~ /^[+-]$/ || # +/-inf or NaN
- $LIB -> _is_one($x->{_d})); # already an integer
+ if ($x->{sign} !~ /^[+-]$/ || # NaN or inf or
+ $LIB->_is_one($x->{_d})) # integer
+ {
+ return $downgrade -> new($x) if defined $downgrade;
+ return $x;
+ }
$x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
$x->{_d} = $LIB->_one(); # d => 1
$x->{sign} = '+' if $x->{sign} eq '-' && $LIB -> _is_zero($x->{_n});
+ return $downgrade -> new($x) if defined $downgrade;
return $x;
}
@@ -1279,6 +1451,8 @@ sub bpow {
($class, $x, $y, @r) = objectify(2, @_);
}
+ return $x if $x->modify('bpow');
+
# $x and/or $y is a NaN
return $x->bnan() if $x->is_nan() || $y->is_nan();
@@ -1304,21 +1478,28 @@ sub bpow {
return $x->binf("+");
}
- if ($x->is_zero()) {
- return $x->binf() if $y->is_negative();
- return $x->bone("+") if $y->is_zero();
+ if ($x -> is_zero()) {
+ return $x -> bone() if $y -> is_zero();
+ return $x -> binf() if $y -> is_negative();
return $x;
- } elsif ($x->is_one()) {
- return $x->round(@r) if $y->is_odd(); # x is -1, y is odd => -1
- return $x->babs()->round(@r); # x is -1, y is even => 1
- } elsif ($y->is_zero()) {
- return $x->bone(@r); # x^0 and x != 0 => 1
- } elsif ($y->is_one()) {
- return $x->round(@r); # x^1 => x
}
- # we don't support complex numbers, so return NaN
- return $x->bnan() if $x->is_negative() && !$y->is_int();
+ # We don't support complex numbers, so upgrade or return NaN.
+
+ if ($x -> is_negative() && !$y -> is_int()) {
+ return $upgrade -> bpow($upgrade -> new($x), $y, @r)
+ if defined $upgrade;
+ return $x -> bnan();
+ }
+
+ if ($x -> is_one("+") || $y -> is_one()) {
+ return $x;
+ }
+
+ if ($x -> is_one("-")) {
+ return $x if $y -> is_odd();
+ return $x -> bneg();
+ }
# (a/b)^-(c/d) = (b/a)^(c/d)
($x->{_n}, $x->{_d}) = ($x->{_d}, $x->{_n}) if $y->is_negative();
@@ -1348,11 +1529,11 @@ sub blog {
# $x->blog(undef) signals that the base is Euler's number.
if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
- # E.g., Math::BigFloat->blog(256, 2)
+ # E.g., Math::BigRat->blog(256, 2)
($class, $x, $base, @r) =
defined $_[2] ? objectify(2, @_) : objectify(1, @_);
} else {
- # E.g., Math::BigFloat::blog(256, 2) or $x->blog(2)
+ # E.g., Math::BigRat::blog(256, 2) or $x->blog(2)
($class, $x, $base, @r) =
defined $_[1] ? objectify(2, @_) : objectify(1, @_);
}
@@ -1393,20 +1574,50 @@ sub blog {
return $x -> binf($sign);
}
+ # Now take care of the cases where $x and/or $base is 1/N.
+ #
+ # log(1/N) / log(B) = -log(N)/log(B)
+ # log(1/N) / log(1/B) = log(N)/log(B)
+ # log(N) / log(1/B) = -log(N)/log(B)
+
+ my $neg = 0;
+ if ($x -> numerator() -> is_one()) {
+ $x -> binv();
+ $neg = !$neg;
+ }
+ if (defined(blessed($base)) && $base -> isa($class)) {
+ if ($base -> numerator() -> is_one()) {
+ $base = $base -> copy() -> binv();
+ $neg = !$neg;
+ }
+ }
+
+ # disable upgrading and downgrading
+
+ require Math::BigFloat;
+ my $upg = Math::BigFloat -> upgrade();
+ my $dng = Math::BigFloat -> downgrade();
+ Math::BigFloat -> upgrade(undef);
+ Math::BigFloat -> downgrade(undef);
+
# At this point we are done handling all exception cases and trivial cases.
$base = Math::BigFloat -> new($base) if defined $base;
+ my $xnum = Math::BigFloat -> new($LIB -> _str($x->{_n}));
+ my $xden = Math::BigFloat -> new($LIB -> _str($x->{_d}));
+ my $xstr = $xnum -> bdiv($xden) -> blog($base, @r) -> bsstr();
- my $xn = Math::BigFloat -> new($LIB -> _str($x->{_n}));
- my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
+ # reset upgrading and downgrading
- my $xtmp = Math::BigRat -> new($xn -> bdiv($xd) -> blog($base, @r) -> bsstr());
+ Math::BigFloat -> upgrade($upg);
+ Math::BigFloat -> downgrade($dng);
- $x -> {sign} = $xtmp -> {sign};
- $x -> {_n} = $xtmp -> {_n};
- $x -> {_d} = $xtmp -> {_d};
+ my $xobj = Math::BigRat -> new($xstr);
+ $x -> {sign} = $xobj -> {sign};
+ $x -> {_n} = $xobj -> {_n};
+ $x -> {_d} = $xobj -> {_d};
- return $x;
+ return $neg ? $x -> bneg() : $x;
}
sub bexp {
@@ -1513,13 +1724,18 @@ sub bnok {
($class, $x, $y, @r) = objectify(2, @_);
}
- my $xint = Math::BigInt -> new($x -> bint() -> bsstr());
- my $yint = Math::BigInt -> new($y -> bint() -> bsstr());
+ return $x->bnan() if $x->is_nan() || $y->is_nan();
+ return $x->bnan() if (($x->is_finite() && !$x->is_int()) ||
+ ($y->is_finite() && !$y->is_int()));
+
+ my $xint = Math::BigInt -> new($x -> bstr());
+ my $yint = Math::BigInt -> new($y -> bstr());
$xint -> bnok($yint);
+ my $xrat = Math::BigRat -> new($xint);
- $x -> {sign} = $xint -> {sign};
- $x -> {_n} = $xint -> {_n};
- $x -> {_d} = $xint -> {_d};
+ $x -> {sign} = $xrat -> {sign};
+ $x -> {_n} = $xrat -> {_n};
+ $x -> {_d} = $xrat -> {_d};
return $x;
}
@@ -1570,7 +1786,7 @@ sub bmodpow {
my $yint = Math::BigInt -> new($y -> copy() -> bint());
my $mint = Math::BigInt -> new($m -> copy() -> bint());
- $xint -> bmodpow($y, $m, @r);
+ $xint -> bmodpow($yint, $mint, @r);
my $xtmp = Math::BigRat -> new($xint -> bsstr());
$x -> {sign} = $xtmp -> {sign};
@@ -1592,7 +1808,7 @@ sub bmodinv {
my $xint = Math::BigInt -> new($x -> copy() -> bint());
my $yint = Math::BigInt -> new($y -> copy() -> bint());
- $xint -> bmodinv($y, @r);
+ $xint -> bmodinv($yint, @r);
my $xtmp = Math::BigRat -> new($xint -> bsstr());
$x -> {sign} = $xtmp -> {sign};
@@ -1651,7 +1867,7 @@ sub bsqrt {
}
sub blsft {
- my ($class, $x, $y, $b, @r) = objectify(2, @_);
+ my ($class, $x, $y, $b) = objectify(2, @_);
$b = 2 if !defined $b;
$b = $class -> new($b) unless ref($b) && $b -> isa($class);
@@ -1665,7 +1881,7 @@ sub blsft {
}
sub brsft {
- my ($class, $x, $y, $b, @r) = objectify(2, @_);
+ my ($class, $x, $y, $b) = objectify(2, @_);
$b = 2 if !defined $b;
$b = $class -> new($b) unless ref($b) && $b -> isa($class);
@@ -1776,15 +1992,24 @@ sub bnot {
# round
sub round {
- $_[0];
+ my $x = shift;
+ return $downgrade -> new($x) if defined($downgrade) &&
+ ($x -> is_int() || $x -> is_inf() || $x -> is_nan());
+ $x;
}
sub bround {
- $_[0];
+ my $x = shift;
+ return $downgrade -> new($x) if defined($downgrade) &&
+ ($x -> is_int() || $x -> is_inf() || $x -> is_nan());
+ $x;
}
sub bfround {
- $_[0];
+ my $x = shift;
+ return $downgrade -> new($x) if defined($downgrade) &&
+ ($x -> is_int() || $x -> is_inf() || $x -> is_nan());
+ $x;
}
##############################################################################
@@ -1803,9 +2028,9 @@ sub bcmp {
if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/) {
# $x is NaN and/or $y is NaN
- return undef if $x->{sign} eq $nan || $y->{sign} eq $nan;
+ return if $x->{sign} eq $nan || $y->{sign} eq $nan;
# $x and $y are both either +inf or -inf
- return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
+ return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
# $x = +inf and $y < +inf
return +1 if $x->{sign} eq '+inf';
# $x = -inf and $y > -inf
@@ -1850,9 +2075,9 @@ sub bacmp {
if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) {
# handle +-inf and NaN
- return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
- return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
- return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
+ return if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
+ return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
+ return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
return -1;
}
@@ -1864,7 +2089,7 @@ sub bacmp {
sub beq {
my $self = shift;
my $selfref = ref $self;
- my $class = $selfref || $self;
+ #my $class = $selfref || $self;
croak 'beq() is an instance method, not a class method' unless $selfref;
croak 'Wrong number of arguments for beq()' unless @_ == 1;
@@ -1876,7 +2101,7 @@ sub beq {
sub bne {
my $self = shift;
my $selfref = ref $self;
- my $class = $selfref || $self;
+ #my $class = $selfref || $self;
croak 'bne() is an instance method, not a class method' unless $selfref;
croak 'Wrong number of arguments for bne()' unless @_ == 1;
@@ -1888,7 +2113,7 @@ sub bne {
sub blt {
my $self = shift;
my $selfref = ref $self;
- my $class = $selfref || $self;
+ #my $class = $selfref || $self;
croak 'blt() is an instance method, not a class method' unless $selfref;
croak 'Wrong number of arguments for blt()' unless @_ == 1;
@@ -1900,7 +2125,7 @@ sub blt {
sub ble {
my $self = shift;
my $selfref = ref $self;
- my $class = $selfref || $self;
+ #my $class = $selfref || $self;
croak 'ble() is an instance method, not a class method' unless $selfref;
croak 'Wrong number of arguments for ble()' unless @_ == 1;
@@ -1912,7 +2137,7 @@ sub ble {
sub bgt {
my $self = shift;
my $selfref = ref $self;
- my $class = $selfref || $self;
+ #my $class = $selfref || $self;
croak 'bgt() is an instance method, not a class method' unless $selfref;
croak 'Wrong number of arguments for bgt()' unless @_ == 1;
@@ -1924,7 +2149,7 @@ sub bgt {
sub bge {
my $self = shift;
my $selfref = ref $self;
- my $class = $selfref || $self;
+ #my $class = $selfref || $self;
croak 'bge() is an instance method, not a class method'
unless $selfref;
@@ -1943,7 +2168,17 @@ sub numify {
# Non-finite number.
- return $x->bstr() if $x->{sign} !~ /^[+-]$/;
+ if ($x -> is_nan()) {
+ require Math::Complex;
+ my $inf = $Math::Complex::Inf;
+ return $inf - $inf;
+ }
+
+ if ($x -> is_inf()) {
+ require Math::Complex;
+ my $inf = $Math::Complex::Inf;
+ return $x -> is_negative() ? -$inf : $inf;
+ }
# Finite number.
@@ -1956,34 +2191,70 @@ sub numify {
}
sub as_int {
- my ($self, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
+ my ($class, $x) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
- # NaN, inf etc
- return Math::BigInt->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
+ return $x -> copy() if $x -> isa("Math::BigInt");
- my $u = Math::BigInt->bzero();
- $u->{value} = $LIB->_div($LIB->_copy($x->{_n}), $x->{_d}); # 22/7 => 3
- $u->bneg if $x->{sign} eq '-'; # no negative zero
- $u;
+ # disable upgrading and downgrading
+
+ require Math::BigInt;
+ my $upg = Math::BigInt -> upgrade();
+ my $dng = Math::BigInt -> downgrade();
+ Math::BigInt -> upgrade(undef);
+ Math::BigInt -> downgrade(undef);
+
+ my $y;
+ if ($x -> is_inf()) {
+ $y = Math::BigInt -> binf($x->sign());
+ } elsif ($x -> is_nan()) {
+ $y = Math::BigInt -> bnan();
+ } else {
+ my $int = $LIB -> _div($LIB -> _copy($x->{_n}), $x->{_d}); # 22/7 => 3
+ $y = Math::BigInt -> new($LIB -> _str($int));
+ $y = $y -> bneg() if $x -> is_neg();
+ }
+
+ # reset upgrading and downgrading
+
+ Math::BigInt -> upgrade($upg);
+ Math::BigInt -> downgrade($dng);
+
+ return $y;
}
sub as_float {
- # return N/D as Math::BigFloat
+ my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
- # set up parameters
- my ($class, $x, @r) = (ref($_[0]), @_);
- # objectify is costly, so avoid it
- ($class, $x, @r) = objectify(1, @_) unless ref $_[0];
+ return $x -> copy() if $x -> isa("Math::BigFloat");
- # NaN, inf etc
- return Math::BigFloat->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
+ # disable upgrading and downgrading
- my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
- my $xflt = Math::BigFloat -> new($LIB -> _str($x->{_n}));
- $xflt -> {sign} = $x -> {sign};
- $xflt -> bdiv($xd, @r);
+ require Math::BigFloat;
+ my $upg = Math::BigFloat -> upgrade();
+ my $dng = Math::BigFloat -> downgrade();
+ Math::BigFloat -> upgrade(undef);
+ Math::BigFloat -> downgrade(undef);
+
+ my $y;
+ if ($x -> is_inf()) {
+ $y = Math::BigFloat -> binf($x->sign());
+ } elsif ($x -> is_nan()) {
+ $y = Math::BigFloat -> bnan();
+ } else {
+ $y = Math::BigFloat -> new($LIB -> _str($x->{_n}));
+ $y -> {sign} = $x -> {sign};
+ unless ($LIB -> _is_one($x->{_d})) {
+ my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
+ $y -> bdiv($xd, @r);
+ }
+ }
+
+ # reset upgrading and downgrading
- return $xflt;
+ Math::BigFloat -> upgrade($upg);
+ Math::BigFloat -> downgrade($dng);
+
+ return $y;
}
sub as_bin {
@@ -2019,18 +2290,27 @@ sub as_oct {
sub from_hex {
my $class = shift;
- $class->new(@_);
+ # The relationship should probably go the otherway, i.e, that new() calls
+ # from_hex(). Fixme!
+ my ($x, @r) = @_;
+ $x =~ s|^\s*(?:0?[Xx]_*)?|0x|;
+ $class->new($x, @r);
}
sub from_bin {
my $class = shift;
- $class->new(@_);
+ # The relationship should probably go the otherway, i.e, that new() calls
+ # from_bin(). Fixme!
+ my ($x, @r) = @_;
+ $x =~ s|^\s*(?:0?[Bb]_*)?|0b|;
+ $class->new($x, @r);
}
sub from_oct {
my $class = shift;
+ # Why is this different from from_hex() and from_bin()? Fixme!
my @parts;
for my $c (@_) {
push @parts, Math::BigInt->from_oct($c);
@@ -2043,57 +2323,101 @@ sub from_oct {
sub import {
my $class = shift;
- my $l = scalar @_;
- my $lib = ''; my @a;
- my $try = 'try';
-
- for (my $i = 0; $i < $l ; $i++) {
- if ($_[$i] eq ':constant') {
- # this rest causes overlord er load to step in
- overload::constant float => sub { $class->new(shift); };
+ my @a; # unrecognized arguments
+ my $lib_param = '';
+ my $lib_value = '';
+
+ while (@_) {
+ my $param = shift;
+
+ # Enable overloading of constants.
+
+ if ($param eq ':constant') {
+ overload::constant
+
+ integer => sub {
+ $class -> new(shift);
+ },
+
+ float => sub {
+ $class -> new(shift);
+ },
+
+ binary => sub {
+ # E.g., a literal 0377 shall result in an object whose value
+ # is decimal 255, but new("0377") returns decimal 377.
+ return $class -> from_oct($_[0]) if $_[0] =~ /^0_*[0-7]/;
+ $class -> new(shift);
+ };
+ next;
}
- # elsif ($_[$i] eq 'upgrade')
- # {
- # # this causes upgrading
- # $upgrade = $_[$i+1]; # or undef to disable
- # $i++;
- # }
- elsif ($_[$i] eq 'downgrade') {
- # this causes downgrading
- $downgrade = $_[$i+1]; # or undef to disable
- $i++;
- } elsif ($_[$i] =~ /^(lib|try|only)\z/) {
- $lib = $_[$i+1] || ''; # default Calc
- $try = $1; # lib, try or only
- $i++;
- } elsif ($_[$i] eq 'with') {
- # this argument is no longer used
- #$LIB = $_[$i+1] || 'Math::BigInt::Calc'; # default Math::BigInt::Calc
- $i++;
- } else {
- push @a, $_[$i];
+
+ # Upgrading.
+
+ if ($param eq 'upgrade') {
+ $class -> upgrade(shift);
+ next;
}
- }
- require Math::BigInt;
- # let use Math::BigInt lib => 'GMP'; use Math::BigRat; still have GMP
- if ($lib ne '') {
- my @c = split /\s*,\s*/, $lib;
- foreach (@c) {
- $_ =~ tr/a-zA-Z0-9://cd; # limit to sane characters
+ # Downgrading.
+
+ if ($param eq 'downgrade') {
+ $class -> downgrade(shift);
+ next;
}
- $lib = join(",", @c);
+
+ # Accuracy.
+
+ if ($param eq 'accuracy') {
+ $class -> accuracy(shift);
+ next;
+ }
+
+ # Precision.
+
+ if ($param eq 'precision') {
+ $class -> precision(shift);
+ next;
+ }
+
+ # Rounding mode.
+
+ if ($param eq 'round_mode') {
+ $class -> round_mode(shift);
+ next;
+ }
+
+ # Backend library.
+
+ if ($param =~ /^(lib|try|only)\z/) {
+ # alternative library
+ $lib_param = $param; # "lib", "try", or "only"
+ $lib_value = shift;
+ next;
+ }
+
+ if ($param eq 'with') {
+ # alternative class for our private parts()
+ # XXX: no longer supported
+ # $LIB = shift() || 'Calc';
+ # carp "'with' is no longer supported, use 'lib', 'try', or 'only'";
+ shift;
+ next;
+ }
+
+ # Unrecognized parameter.
+
+ push @a, $param;
}
- my @import = ('objectify');
- push @import, $try => $lib if $lib ne '';
- # LIB already loaded, so feed it our lib arguments
- Math::BigInt->import(@import);
+ require Math::BigInt;
- $LIB = Math::BigFloat->config("lib");
+ my @import = ('objectify');
+ push @import, $lib_param, $lib_value if $lib_param ne '';
+ Math::BigInt -> import(@import);
- # register us with LIB to get notified of future lib changes
- Math::BigInt::_register_callback($class, sub { $LIB = $_[0]; });
+ # find out which one was actually loaded
+ $LIB = Math::BigInt -> config("lib");
# any non :constant stuff is handled by Exporter (loaded by parent class)
# even if @_ is empty, to give it a chance
@@ -2109,7 +2433,7 @@ __END__
=head1 NAME
-Math::BigRat - Arbitrary big rational numbers
+Math::BigRat - arbitrary size rational number math package
=head1 SYNOPSIS
@@ -2201,6 +2525,16 @@ Returns a copy of the denominator (the part under the line) as positive BigInt.
Return a list consisting of (signed) numerator and (unsigned) denominator as
BigInts.
+=item dparts()
+
+Returns the integer part and the fraction part.
+
+=item fparts()
+
+Returns the smallest possible numerator and denominator so that the numerator
+divided by the denominator gives back the original value. For finite numbers,
+both values are integers. Mnemonic: fraction.
+
=item numify()
my $y = $x->numify();
@@ -2513,7 +2847,13 @@ Subtracts $y from $x and returns the result.
In scalar context, divides $x by $y and returns the result. In list context,
does floored division (F-division), returning an integer $q and a remainder $r
so that $x = $q * $y + $r. The remainer (modulo) is equal to what is returned
-by C<$x->bmod($y)>.
+by C<< $x->bmod($y) >>.
+
+=item binv()
+
+ $x->binv();
+
+Inverse of $x.
=item bdec()
@@ -2695,6 +3035,70 @@ supported.
=back
+=head1 NUMERIC LITERALS
+
+After C<use Math::BigRat ':constant'> all numeric literals in the given scope
+are converted to C<Math::BigRat> objects. This conversion happens at compile
+time. Every non-integer is convert to a NaN.
+
+For example,
+
+ perl -MMath::BigRat=:constant -le 'print 2**150'
+
+prints the exact value of C<2**150>. Note that without conversion of constants
+to objects the expression C<2**150> is calculated using Perl scalars, which
+leads to an inaccurate result.
+
+Please note that strings are not affected, so that
+
+ use Math::BigRat qw/:constant/;
+
+ $x = "1234567890123456789012345678901234567890"
+ + "123456789123456789";
+
+does give you what you expect. You need an explicit Math::BigRat->new() around
+at least one of the operands. You should also quote large constants to prevent
+loss of precision:
+
+ use Math::BigRat;
+
+ $x = Math::BigRat->new("1234567889123456789123456789123456789");
+
+Without the quotes Perl first converts the large number to a floating point
+constant at compile time, and then converts the result to a Math::BigRat object
+at run time, which results in an inaccurate result.
+
+=head2 Hexadecimal, octal, and binary floating point literals
+
+Perl (and this module) accepts hexadecimal, octal, and binary floating point
+literals, but use them with care with Perl versions before v5.32.0, because some
+versions of Perl silently give the wrong result. Below are some examples of
+different ways to write the number decimal 314.
+
+Hexadecimal floating point literals:
+
+ 0x1.3ap+8 0X1.3AP+8
+ 0x1.3ap8 0X1.3AP8
+ 0x13a0p-4 0X13A0P-4
+
+Octal floating point literals (with "0" prefix):
+
+ 01.164p+8 01.164P+8
+ 01.164p8 01.164P8
+ 011640p-4 011640P-4
+
+Octal floating point literals (with "0o" prefix) (requires v5.34.0):
+
+ 0o1.164p+8 0O1.164P+8
+ 0o1.164p8 0O1.164P8
+ 0o11640p-4 0O11640P-4
+
+Binary floating point literals:
+
+ 0b1.0011101p+8 0B1.0011101P+8
+ 0b1.0011101p8 0B1.0011101P8
+ 0b10011101000p-2 0B10011101000P-2
+
=head1 BUGS
Please report any bugs or feature requests to
@@ -2714,43 +3118,25 @@ You can also look for information at:
=over 4
-=item * RT: CPAN's request tracker
-
-L<https://rt.cpan.org/Public/Dist/Display.html?Name=Math-BigRat>
-
-=item * AnnoCPAN: Annotated CPAN documentation
+=item * GitHub
-L<http://annocpan.org/dist/Math-BigRat>
+L<https://github.com/pjacklam/p5-Math-BigRat>
-=item * CPAN Ratings
+=item * RT: CPAN's request tracker
-L<http://cpanratings.perl.org/dist/Math-BigRat>
+L<https://rt.cpan.org/Dist/Display.html?Name=Math-BigRat>
-=item * Search CPAN
+=item * MetaCPAN
-L<http://search.cpan.org/dist/Math-BigRat/>
+L<https://metacpan.org/release/Math-BigRat>
=item * CPAN Testers Matrix
L<http://matrix.cpantesters.org/?dist=Math-BigRat>
-=item * The Bignum mailing list
-
-=over 4
-
-=item * Post to mailing list
-
-C<bignum at lists.scsys.co.uk>
-
-=item * View mailing list
-
-L<http://lists.scsys.co.uk/pipermail/bignum/>
-
-=item * Subscribe/Unsubscribe
-
-L<http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/bignum>
+=item * CPAN Ratings
-=back
+L<https://cpanratings.perl.org/dist/Math-BigRat>
=back
@@ -2774,7 +3160,7 @@ Tels L<http://bloodgate.com/> 2001-2009.
=item *
-Maintained by Peter John Acklam <pjacklam@online.no> 2011-
+Maintained by Peter John Acklam <pjacklam@gmail.com> 2011-
=back