summaryrefslogtreecommitdiff
path: root/lib/Math/BigInt.pm
diff options
context:
space:
mode:
authorRafael Garcia-Suarez <rgarciasuarez@gmail.com>2003-07-04 20:58:05 +0000
committerRafael Garcia-Suarez <rgarciasuarez@gmail.com>2003-07-04 20:58:05 +0000
commit990fb837ac6356023668c709e35770d2e63ec006 (patch)
tree84790f8204d4d64e5b9ae4b72620d6c22f8e5199 /lib/Math/BigInt.pm
parent2a30c5e0c7700acf7c1205bda81f1853b9257109 (diff)
downloadperl-990fb837ac6356023668c709e35770d2e63ec006.tar.gz
Upgrade to Math::BigInt v1.65, Math::BigRat v0.10,
and bignum v0.14. p4raw-id: //depot/perl@20000
Diffstat (limited to 'lib/Math/BigInt.pm')
-rw-r--r--lib/Math/BigInt.pm423
1 files changed, 309 insertions, 114 deletions
diff --git a/lib/Math/BigInt.pm b/lib/Math/BigInt.pm
index f59395c58e..75a9be7e08 100644
--- a/lib/Math/BigInt.pm
+++ b/lib/Math/BigInt.pm
@@ -18,13 +18,14 @@ package Math::BigInt;
my $class = "Math::BigInt";
require 5.005;
-$VERSION = '1.64_01';
-$VERSION = eval $VERSION;
+$VERSION = '1.65';
use Exporter;
@ISA = qw( Exporter );
@EXPORT_OK = qw( objectify _swap bgcd blcm);
use vars qw/$round_mode $accuracy $precision $div_scale $rnd_mode/;
use vars qw/$upgrade $downgrade/;
+# the following are internal and should never be accessed from the outside
+use vars qw/$_trap_nan $_trap_inf/;
use strict;
# Inside overload, the first arg is always an object. If the original code had
@@ -115,13 +116,8 @@ use overload
##############################################################################
# global constants, flags and accessory
-use constant MB_NEVER_ROUND => 0x0001;
-
-my $NaNOK=1; # are NaNs ok?
-my $nan = 'NaN'; # constants for easier life
-
-my $CALC = 'Math::BigInt::Calc'; # module to do low level math
-my $IMPORT = 0; # did import() yet?
+# these are public, but their usage is not recommended, use the accessor
+# methods instead
$round_mode = 'even'; # one of 'even', 'odd', '+inf', '-inf', 'zero' or 'trunc'
$accuracy = undef;
@@ -131,6 +127,18 @@ $div_scale = 40;
$upgrade = undef; # default is no upgrade
$downgrade = undef; # default is no downgrade
+# these are internally, and not to be used from the outside
+
+use constant MB_NEVER_ROUND => 0x0001;
+
+$_trap_nan = 0; # are NaNs ok? set w/ config()
+$_trap_inf = 0; # are infs ok? set w/ config()
+my $nan = 'NaN'; # constants for easier life
+
+my $CALC = 'Math::BigInt::Calc'; # module to do the low level math
+my $IMPORT = 0; # was import() called yet?
+ # used to make require work
+
##############################################################################
# the old code had $rnd_mode, so we need to support it, too
@@ -152,11 +160,13 @@ sub round_mode
if (defined $_[0])
{
my $m = shift;
- die "Unknown round mode $m"
- if $m !~ /^(even|odd|\+inf|\-inf|zero|trunc)$/;
+ if ($m !~ /^(even|odd|\+inf|\-inf|zero|trunc)$/)
+ {
+ require Carp; Carp::croak ("Unknown round mode '$m'");
+ }
return ${"${class}::round_mode"} = $m;
}
- return ${"${class}::round_mode"};
+ ${"${class}::round_mode"};
}
sub upgrade
@@ -171,7 +181,7 @@ sub upgrade
my $u = shift;
return ${"${class}::upgrade"} = $u;
}
- return ${"${class}::upgrade"};
+ ${"${class}::upgrade"};
}
sub downgrade
@@ -186,21 +196,24 @@ sub downgrade
my $u = shift;
return ${"${class}::downgrade"} = $u;
}
- return ${"${class}::downgrade"};
+ ${"${class}::downgrade"};
}
sub div_scale
{
no strict 'refs';
- # make Class->round_mode() work
+ # make Class->div_scale() work
my $self = shift;
my $class = ref($self) || $self || __PACKAGE__;
if (defined $_[0])
{
- die ('div_scale must be greater than zero') if $_[0] < 0;
+ if ($_[0] < 0)
+ {
+ require Carp; Carp::croak ('div_scale must be greater than zero');
+ }
${"${class}::div_scale"} = shift;
}
- return ${"${class}::div_scale"};
+ ${"${class}::div_scale"};
}
sub accuracy
@@ -218,21 +231,39 @@ sub accuracy
if (@_ > 0)
{
my $a = shift;
- die ('accuracy must not be zero') if defined $a && $a == 0;
+ # convert objects to scalars to avoid deep recursion. If object doesn't
+ # have numify(), then hopefully it will have overloading for int() and
+ # boolean test without wandering into a deep recursion path...
+ $a = $a->numify() if ref($a) && $a->can('numify');
+
+ if (defined $a)
+ {
+ # also croak on non-numerical
+ if (!$a || $a <= 0)
+ {
+ require Carp;
+ Carp::croak ('Argument to accuracy must be greater than zero');
+ }
+ if (int($a) != $a)
+ {
+ require Carp; Carp::croak ('Argument to accuracy must be an integer');
+ }
+ }
if (ref($x))
{
# $object->accuracy() or fallback to global
- $x->bround($a) if defined $a;
- $x->{_a} = $a; # set/overwrite, even if not rounded
- $x->{_p} = undef; # clear P
+ $x->bround($a) if $a; # not for undef, 0
+ $x->{_a} = $a; # set/overwrite, even if not rounded
+ $x->{_p} = undef; # clear P
+ $a = ${"${class}::accuracy"} unless defined $a; # proper return value
}
else
{
# set global
${"${class}::accuracy"} = $a;
- ${"${class}::precision"} = undef; # clear P
+ ${"${class}::precision"} = undef; # clear P
}
- return $a; # shortcut
+ return $a; # shortcut
}
my $r;
@@ -241,7 +272,7 @@ sub accuracy
# but don't return global undef, when $x's accuracy is 0!
$r = ${"${class}::accuracy"} if !defined $r;
$r;
- }
+ }
sub precision
{
@@ -254,24 +285,32 @@ sub precision
my $class = ref($x) || $x || __PACKAGE__;
no strict 'refs';
- # need to set new value?
if (@_ > 0)
{
my $p = shift;
+ # convert objects to scalars to avoid deep recursion. If object doesn't
+ # have numify(), then hopefully it will have overloading for int() and
+ # boolean test without wandering into a deep recursion path...
+ $p = $p->numify() if ref($p) && $p->can('numify');
+ if ((defined $p) && (int($p) != $p))
+ {
+ require Carp; Carp::croak ('Argument to precision must be an integer');
+ }
if (ref($x))
{
# $object->precision() or fallback to global
- $x->bfround($p) if defined $p;
- $x->{_p} = $p; # set/overwrite, even if not rounded
- $x->{_a} = undef; # clear A
+ $x->bfround($p) if $p; # not for undef, 0
+ $x->{_p} = $p; # set/overwrite, even if not rounded
+ $x->{_a} = undef; # clear A
+ $p = ${"${class}::precision"} unless defined $p; # proper return value
}
else
{
# set global
${"${class}::precision"} = $p;
- ${"${class}::accuracy"} = undef; # clear A
+ ${"${class}::accuracy"} = undef; # clear A
}
- return $p; # shortcut
+ return $p; # shortcut
}
my $r;
@@ -280,24 +319,66 @@ sub precision
# but don't return global undef, when $x's precision is 0!
$r = ${"${class}::precision"} if !defined $r;
$r;
- }
+ }
sub config
{
- # return (later set?) configuration data as hash ref
+ # return (or set) configuration data as hash ref
my $class = shift || 'Math::BigInt';
no strict 'refs';
- my $lib = $CALC;
+ if (@_ > 0)
+ {
+ # try to set given options as arguments from hash
+
+ my $args = $_[0];
+ if (ref($args) ne 'HASH')
+ {
+ $args = { @_ };
+ }
+ # these values can be "set"
+ my $set_args = {};
+ foreach my $key (
+ qw/trap_inf trap_nan
+ upgrade downgrade precision accuracy round_mode div_scale/
+ )
+ {
+ $set_args->{$key} = $args->{$key} if exists $args->{$key};
+ delete $args->{$key};
+ }
+ if (keys %$args > 0)
+ {
+ require Carp;
+ Carp::croak ("Illegal key(s) '",
+ join("','",keys %$args),"' passed to $class\->config()");
+ }
+ foreach my $key (keys %$set_args)
+ {
+ if ($key =~ /^trap_(inf|nan)\z/)
+ {
+ ${"${class}::_trap_$1"} = ($set_args->{"trap_$1"} ? 1 : 0);
+ next;
+ }
+ # use a call instead of just setting the $variable to check argument
+ $class->$key($set_args->{$key});
+ }
+ }
+
+ # now return actual configuration
+
my $cfg = {
- lib => $lib,
- lib_version => ${"${lib}::VERSION"},
+ lib => $CALC,
+ lib_version => ${"${CALC}::VERSION"},
class => $class,
+ trap_nan => ${"${class}::_trap_nan"},
+ trap_inf => ${"${class}::_trap_inf"},
+ version => ${"${class}::VERSION"},
};
- foreach (
- qw/upgrade downgrade precision accuracy round_mode VERSION div_scale/)
+ foreach my $key (qw/
+ upgrade downgrade precision accuracy round_mode div_scale
+ /)
{
- $cfg->{lc($_)} = ${"${class}::$_"};
+ $cfg->{$key} = ${"${class}::$key"};
};
$cfg;
}
@@ -416,6 +497,10 @@ sub new
# remove sign without touching wanted to make it work with constants
my $t = $wanted; $t =~ s/^[+-]//; $ref = \$t;
}
+ # force to string version (otherwise Pari is unhappy about overflowed
+ # constants, for instance)
+ # not good, BigInt shouldn't need to know about alternative libs:
+ # $ref = \"$$ref" if $CALC eq 'Math::BigInt::Pari';
$self->{value} = $CALC->_new($ref);
no strict 'refs';
if ( (defined $a) || (defined $p)
@@ -439,8 +524,10 @@ sub new
my ($mis,$miv,$mfv,$es,$ev) = _split(\$wanted);
if (!ref $mis)
{
- die "$wanted is not a number initialized to $class" if !$NaNOK;
- #print "NaN 1\n";
+ if ($_trap_nan)
+ {
+ require Carp; Carp::croak("$wanted is not a number in $class");
+ }
$self->{value} = $CALC->_zero();
$self->{sign} = $nan;
return $self;
@@ -461,6 +548,10 @@ sub new
my $diff = $e - CORE::length($$mfv);
if ($diff < 0) # Not integer
{
+ if ($_trap_nan)
+ {
+ require Carp; Carp::croak("$wanted not an integer in $class");
+ }
#print "NOI 1\n";
return $upgrade->new($wanted,$a,$p,$r) if defined $upgrade;
$self->{sign} = $nan;
@@ -468,7 +559,7 @@ sub new
else # diff >= 0
{
# adjust fraction and add it to value
- # print "diff > 0 $$miv\n";
+ #print "diff > 0 $$miv\n";
$$miv = $$miv . ($$mfv . '0' x $diff);
}
}
@@ -477,6 +568,10 @@ sub new
if ($$mfv ne '') # e <= 0
{
# fraction and negative/zero E => NOI
+ if ($_trap_nan)
+ {
+ require Carp; Carp::croak("$wanted not an integer in $class");
+ }
#print "NOI 2 \$\$mfv '$$mfv'\n";
return $upgrade->new($wanted,$a,$p,$r) if defined $upgrade;
$self->{sign} = $nan;
@@ -488,6 +583,10 @@ sub new
$e = abs($e);
if ($$miv !~ s/0{$e}$//) # can strip so many zero's?
{
+ if ($_trap_nan)
+ {
+ require Carp; Carp::croak("$wanted not an integer in $class");
+ }
#print "NOI 3\n";
return $upgrade->new($wanted,$a,$p,$r) if defined $upgrade;
$self->{sign} = $nan;
@@ -512,9 +611,14 @@ sub bnan
{
my $c = $self; $self = {}; bless $self, $c;
}
+ no strict 'refs';
+ if (${"${class}::_trap_nan"})
+ {
+ require Carp;
+ Carp::croak ("Tried to set $self to NaN in $class\::bnan()");
+ }
$self->import() if $IMPORT == 0; # make require work
return if $self->modify('bnan');
- my $c = ref($self);
if ($self->can('_bnan'))
{
# use subclass to initialize
@@ -541,9 +645,14 @@ sub binf
{
my $c = $self; $self = {}; bless $self, $c;
}
+ no strict 'refs';
+ if (${"${class}::_trap_inf"})
+ {
+ require Carp;
+ Carp::croak ("Tried to set $self to +-inf in $class\::binfn()");
+ }
$self->import() if $IMPORT == 0; # make require work
return if $self->modify('binf');
- my $c = ref($self);
if ($self->can('_binf'))
{
# use subclass to initialize
@@ -572,7 +681,7 @@ sub bzero
}
$self->import() if $IMPORT == 0; # make require work
return if $self->modify('bzero');
-
+
if ($self->can('_bzero'))
{
# use subclass to initialize
@@ -609,7 +718,7 @@ sub bone
my $self = shift;
my $sign = shift; $sign = '+' if !defined $sign || $sign ne '-';
$self = $class if !defined $self;
-
+
if (!ref($self))
{
my $c = $self; $self = {}; bless $self, $c;
@@ -709,9 +818,14 @@ sub _find_round_parameters
# After any operation or when calling round(), the result is rounded by
# regarding the A & P from arguments, local parameters, or globals.
+ # !!!!!!! If you change this, remember to change round(), too! !!!!!!!!!!
+
# This procedure finds the round parameters, but it is for speed reasons
# duplicated in round. Otherwise, it is tested by the testsuite and used
# by fdiv().
+
+ # returns ($self) or ($self,$a,$p,$r) - sets $self to NaN of both A and P
+ # were requested/defined (locally or globally or both)
my ($self,$a,$p,$r,@args) = @_;
# $a accuracy, if given by caller
@@ -720,7 +834,7 @@ sub _find_round_parameters
# @args all 'other' arguments (0 for unary, 1 for binary ops)
# leave bigfloat parts alone
- return ($self) if exists $self->{_f} && $self->{_f} & MB_NEVER_ROUND != 0;
+ return ($self) if exists $self->{_f} && ($self->{_f} & MB_NEVER_ROUND) != 0;
my $c = ref($self); # find out class of argument(s)
no strict 'refs';
@@ -747,17 +861,23 @@ sub _find_round_parameters
# if still none defined, use globals (#2)
$a = ${"$c\::accuracy"} unless defined $a;
$p = ${"$c\::precision"} unless defined $p;
+
+ # A == 0 is useless, so undef it to signal no rounding
+ $a = undef if defined $a && $a == 0;
# no rounding today?
return ($self) unless defined $a || defined $p; # early out
# set A and set P is an fatal error
- return ($self->bnan()) if defined $a && defined $p;
+ return ($self->bnan()) if defined $a && defined $p; # error
$r = ${"$c\::round_mode"} unless defined $r;
- die "Unknown round mode '$r'" if $r !~ /^(even|odd|\+inf|\-inf|zero|trunc)$/;
-
- return ($self,$a,$p,$r);
+ if ($r !~ /^(even|odd|\+inf|\-inf|zero|trunc)$/)
+ {
+ require Carp; Carp::croak ("Unknown round mode '$r'");
+ }
+
+ ($self,$a,$p,$r);
}
sub round
@@ -774,7 +894,7 @@ sub round
# @args all 'other' arguments (0 for unary, 1 for binary ops)
# leave bigfloat parts alone
- return ($self) if exists $self->{_f} && $self->{_f} & MB_NEVER_ROUND != 0;
+ return ($self) if exists $self->{_f} && ($self->{_f} & MB_NEVER_ROUND) != 0;
my $c = ref($self); # find out class of argument(s)
no strict 'refs';
@@ -802,6 +922,9 @@ sub round
$a = ${"$c\::accuracy"} unless defined $a;
$p = ${"$c\::precision"} unless defined $p;
+ # A == 0 is useless, so undef it to signal no rounding
+ $a = undef if defined $a && $a == 0;
+
# no rounding today?
return $self unless defined $a || defined $p; # early out
@@ -809,7 +932,10 @@ sub round
return $self->bnan() if defined $a && defined $p;
$r = ${"$c\::round_mode"} unless defined $r;
- die "Unknown round mode '$r'" if $r !~ /^(even|odd|\+inf|\-inf|zero|trunc)$/;
+ if ($r !~ /^(even|odd|\+inf|\-inf|zero|trunc)$/)
+ {
+
+ }
# now round, by calling either fround or ffround:
if (defined $a)
@@ -1084,7 +1210,7 @@ sub blog
# not implemented yet
my ($self,$x,$base,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
- return $upgrade->blog($x,$base,$a,$p,$r) if defined $upgrade;
+ return $upgrade->blog($upgrade->new($x),$base,$a,$p,$r) if defined $upgrade;
return $x->bnan();
}
@@ -1197,7 +1323,7 @@ sub is_one
# we don't need $self, so undef instead of ref($_[0]) make it slightly faster
my ($self,$x,$sign) = ref($_[0]) ? (undef,@_) : objectify(1,@_);
- $sign = '' if !defined $sign; $sign = '+' if $sign ne '-';
+ $sign = '+' if !defined $sign || $sign ne '-';
return 0 if $x->{sign} ne $sign; # -1 != +1, NaN, +-inf aren't either
$CALC->_is_one($x->{value});
@@ -1361,44 +1487,14 @@ sub bdiv
return $self->_div_inf($x,$y)
if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
- return $upgrade->bdiv($upgrade->new($x),$y,@r)
- if defined $upgrade && !$y->isa($self);
-
- $r[3] = $y; # no push!
-
- # 0 / something
- return
- wantarray ? ($x->round(@r),$self->bzero(@r)):$x->round(@r) if $x->is_zero();
-
- # Is $x in the interval [0, $y) (aka $x <= $y) ?
- my $cmp = $CALC->_acmp($x->{value},$y->{value});
- if (($cmp < 0) and (($x->{sign} eq $y->{sign}) or !wantarray))
- {
- return $upgrade->bdiv($upgrade->new($x),$upgrade->new($y),@r)
- if defined $upgrade;
-
- return $x->bzero()->round(@r) unless wantarray;
- my $t = $x->copy(); # make copy first, because $x->bzero() clobbers $x
- return ($x->bzero()->round(@r),$t);
- }
- elsif ($cmp == 0)
- {
- # shortcut, both are the same, so set to +/- 1
- $x->__one( ($x->{sign} ne $y->{sign} ? '-' : '+') );
- return $x unless wantarray;
- return ($x->round(@r),$self->bzero(@r));
- }
return $upgrade->bdiv($upgrade->new($x),$upgrade->new($y),@r)
if defined $upgrade;
+ $r[3] = $y; # no push!
+
# calc new sign and in case $y == +/- 1, return $x
my $xsign = $x->{sign}; # keep
$x->{sign} = ($x->{sign} ne $y->{sign} ? '-' : '+');
- # check for / +-1 (cant use $y->is_one due to '-'
- if ($CALC->_is_one($y->{value}))
- {
- return wantarray ? ($x->round(@r),$self->bzero(@r)) : $x->round(@r);
- }
if (wantarray)
{
@@ -1407,23 +1503,24 @@ sub bdiv
$x->{sign} = '+' if $CALC->_is_zero($x->{value});
$rem->{_a} = $x->{_a};
$rem->{_p} = $x->{_p};
- $x->round(@r);
+ $x->round(@r) if !exists $x->{_f} || ($x->{_f} & MB_NEVER_ROUND) == 0;
if (! $CALC->_is_zero($rem->{value}))
{
$rem->{sign} = $y->{sign};
- $rem = $y-$rem if $xsign ne $y->{sign}; # one of them '-'
+ $rem = $y->copy()->bsub($rem) if $xsign ne $y->{sign}; # one of them '-'
}
else
{
$rem->{sign} = '+'; # dont leave -0
}
- return ($x,$rem->round(@r));
+ $rem->round(@r) if !exists $rem->{_f} || ($rem->{_f} & MB_NEVER_ROUND) == 0;
+ return ($x,$rem);
}
$x->{value} = $CALC->_div($x->{value},$y->{value});
$x->{sign} = '+' if $CALC->_is_zero($x->{value});
- $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ $x->round(@r) if !exists $x->{_f} || ($x->{_f} & MB_NEVER_ROUND) == 0;
$x;
}
@@ -1605,7 +1702,7 @@ sub bmodpow
$num->bone(); # keep ref to $num
my $expbin = $exp->as_bin(); $expbin =~ s/^[-]?0b//; # ignore sign and prefix
- my $len = length($expbin);
+ my $len = CORE::length($expbin);
while (--$len >= 0)
{
if( substr($expbin,$len,1) eq '1')
@@ -1710,7 +1807,7 @@ sub bpow
my $pow2 = $self->__one();
my $y_bin = $y->as_bin(); $y_bin =~ s/^0b//;
- my $len = length($y_bin);
+ my $len = CORE::length($y_bin);
while (--$len > 0)
{
$pow2->bmul($x) if substr($y_bin,$len,1) eq '1'; # is odd?
@@ -2008,13 +2105,14 @@ sub _trailing_zeros
sub bsqrt
{
+ # calculate square root of $x
my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
return $x if $x->modify('bsqrt');
- return $x->bnan() if $x->{sign} ne '+'; # -x or inf or NaN => NaN
- return $x->bzero(@r) if $x->is_zero(); # 0 => 0
- return $x->round(@r) if $x->is_one(); # 1 => 1
+ return $x->bnan() if $x->{sign} !~ /^\+/; # -x or -inf or NaN => NaN
+ return $x if $x->{sign} eq '+inf'; # sqrt(+inf) == inf
+ return $x->round(@r) if $x->is_zero() || $x->is_one(); # 0,1 => 0,1
return $upgrade->bsqrt($x,@r) if defined $upgrade;
@@ -2029,11 +2127,12 @@ sub bsqrt
my $l = int($x->length()/2);
$x->bone(); # keep ref($x), but modify it
- $x->blsft($l,10);
+ $x->blsft($l,10) if $l != 0; # first guess: 1.('0' x (l/2))
my $last = $self->bzero();
my $two = $self->new(2);
- my $lastlast = $x+$two;
+ my $lastlast = $self->bzero();
+ #my $lastlast = $x+$two;
while ($last != $x && $lastlast != $x)
{
$lastlast = $last; $last = $x->copy();
@@ -2044,6 +2143,71 @@ sub bsqrt
$x->round(@r);
}
+sub broot
+ {
+ # calculate $y'th root of $x
+
+ # set up parameters
+ my ($self,$x,$y,@r) = (ref($_[0]),@_);
+ # objectify is costly, so avoid it
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+ {
+ ($self,$x,$y,@r) = objectify(2,@_);
+ }
+
+ return $x if $x->modify('broot');
+
+ # NaN handling: $x ** 1/0, x or y NaN, or y inf/-inf or y == 0
+ return $x->bnan() if $x->{sign} !~ /^\+/ || $y->is_zero() ||
+ $y->{sign} !~ /^\+$/;
+
+ return $x->round(@r)
+ if $x->is_zero() || $x->is_one() || $x->is_inf() || $y->is_one();
+
+ return $upgrade->broot($x,@r) if defined $upgrade;
+
+ if ($CALC->can('_root'))
+ {
+ $x->{value} = $CALC->_root($x->{value},$y->{value});
+ return $x->round(@r);
+ }
+
+ return $x->bsqrt() if $y->bacmp(2) == 0; # 2 => square root
+
+ # since we take at least a cubic root, and only 8 ** 1/3 >= 2 (==2):
+ return $x->bone('+',@r) if $x < 8; # $x=2..7 => 1
+
+ my $org = $x->copy();
+ my $l = int($x->length()/$y->numify());
+
+ $x->bone(); # keep ref($x), but modify it
+ $x->blsft($l,10) if $l != 0; # first guess: 1.('0' x (l/$y))
+
+ my $last = $self->bzero();
+ my $lastlast = $self->bzero();
+ #my $lastlast = $x+$y;
+ my $divider = $self->new(2);
+ my $up = $y-1;
+ print "start $org divider $divider up $up\n";
+ while ($last != $x && $lastlast != $x)
+ {
+ print "at $x ($last $lastlast)\n";
+ $lastlast = $last; $last = $x->copy();
+ print "at $x ($last ",($org / ($x ** $up)),"\n";
+ $x->badd($org / ($x ** 2));
+ $x->bdiv($divider);
+ }
+ print $x ** $y," org ",$org,"\n";
+ # correct overshot
+ while ($x ** $y < $org)
+ {
+ print "correcting $x to ";
+ $x->binc();
+ print "$x ( $x ** $y == ",$x ** $y,")\n";
+ }
+ $x->round(@r);
+ }
+
sub exponent
{
# return a copy of the exponent (here always 0, NaN or 1 for $m == 0)
@@ -2350,7 +2514,7 @@ sub objectify
}
my $up = ${"$a[0]::upgrade"};
- # print "Now in objectify, my class is today $a[0]\n";
+ #print "Now in objectify, my class is today $a[0]\n";
if ($count == 0)
{
while (@_)
@@ -2387,7 +2551,10 @@ sub objectify
}
push @a,@_; # return other params, too
}
- die "$class objectify needs list context" unless wantarray;
+ if (! wantarray)
+ {
+ require Carp; Carp::croak ("$class objectify needs list context");
+ }
${"$a[0]::downgrade"} = $d;
@a;
}
@@ -2453,7 +2620,11 @@ sub import
}
$CALC = $lib, last if $@ eq ''; # no error in loading lib?
}
- die "Couldn't load any math lib, not even the default" if $CALC eq '';
+ if ($CALC eq '')
+ {
+ require Carp;
+ Carp::croak ("Couldn't load any math lib, not even the default");
+ }
}
sub __from_hex
@@ -2619,7 +2790,6 @@ sub as_hex
my $x = shift; $x = $class->new($x) if !ref($x);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
- return '0x0' if $x->is_zero();
my $es = ''; my $s = '';
$s = $x->{sign} if $x->{sign} eq '-';
@@ -2629,6 +2799,8 @@ sub as_hex
}
else
{
+ return '0x0' if $x->is_zero();
+
my $x1 = $x->copy()->babs(); my ($xr,$x10000,$h);
if ($] >= 5.006)
{
@@ -2656,7 +2828,6 @@ sub as_bin
my $x = shift; $x = $class->new($x) if !ref($x);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
- return '0b0' if $x->is_zero();
my $es = ''; my $s = '';
$s = $x->{sign} if $x->{sign} eq '-';
@@ -2666,6 +2837,7 @@ sub as_bin
}
else
{
+ return '0b0' if $x->is_zero();
my $x1 = $x->copy()->babs(); my ($xr,$x10000,$b);
if ($] >= 5.006)
{
@@ -2735,6 +2907,12 @@ Math::BigInt - Arbitrary size integer math package
use Math::BigInt;
+ # or make it faster: install (optional) Math::BigInt::GMP
+ # and always use (it will fall back to pure Perl if the
+ # GMP library is not installed):
+
+ use Math::BigInt lib => 'GMP';
+
# Number creation
$x = Math::BigInt->new($str); # defaults to 0
$nan = Math::BigInt->bnan(); # create a NotANumber
@@ -2765,7 +2943,9 @@ Math::BigInt - Arbitrary size integer math package
$x->digit($n); # return the nth digit, counting from right
$x->digit(-$n); # return the nth digit, counting from left
- # The following all modify their first argument:
+ # The following all modify their first argument. If you want to preserve
+ # $x, use $z = $x->copy()->bXXX($y); See under L<CAVEATS> for why this is
+ # neccessary when mixing $a = $b assigments with non-overloaded math.
$x->bzero(); # set $x to 0
$x->bnan(); # set $x to NaN
@@ -2803,13 +2983,14 @@ Math::BigInt - Arbitrary size integer math package
$x->bnot(); # bitwise not (two's complement)
$x->bsqrt(); # calculate square-root
+ $x->broot($y); # $y'th root of $x (e.g. $y == 3 => cubic root)
$x->bfac(); # factorial of $x (1*2*3*4*..$x)
- $x->round($A,$P,$mode); # round to accuracy or precision using mode $r
+ $x->round($A,$P,$mode); # round to accuracy or precision using mode $mode
$x->bround($N); # accuracy: preserve $N digits
$x->bfround($N); # round to $Nth digit, no-op for BigInts
- # The following do not modify their arguments in BigInt,
+ # The following do not modify their arguments in BigInt (are no-ops),
# but do so in BigFloat:
$x->bfloor(); # return integer less or equal than $x
@@ -3561,7 +3742,7 @@ This is how it works now:
globals enforced upon creation of a number by using
$x = Math::BigInt->new($number,undef,undef):
- use Math::Bigint::SomeSubclass;
+ use Math::BigInt::SomeSubclass;
use Math::BigInt;
Math::BigInt->accuracy(2);
@@ -3767,8 +3948,8 @@ numerical sense, e.g. $m might get minimized.
$x = Math::BigInt->bstr("1234") # string "1234"
$x = "$x"; # same as bstr()
- $x = Math::BigInt->bneg("1234"); # Bigint "-1234"
- $x = Math::BigInt->babs("-12345"); # Bigint "12345"
+ $x = Math::BigInt->bneg("1234"); # BigInt "-1234"
+ $x = Math::BigInt->babs("-12345"); # BigInt "12345"
$x = Math::BigInt->bnorm("-0 00"); # BigInt "0"
$x = bint(1) + bint(2); # BigInt "3"
$x = bint(1) + "2"; # ditto (auto-BigIntify of "2")
@@ -3836,7 +4017,7 @@ so that
do not work. You need an explicit Math::BigInt->new() around one of the
operands. You should also quote large constants to protect loss of precision:
- use Math::Bigint;
+ use Math::BigInt;
$x = Math::BigInt->new('1234567889123456789123456789123456789');
@@ -4006,6 +4187,11 @@ versions to a more sophisticated scheme):
=over 2
+=item broot() does not work
+
+The broot() function in BigInt may only work for small values. This will be
+fixed in a later version.
+
=item Out of Memory!
Under Perl prior to 5.6.0 having an C<use Math::BigInt ':constant';> and
@@ -4313,13 +4499,14 @@ will both result in the proper type due to the way the overloaded math works.
This section also applies to other overloaded math packages, like Math::String.
-One solution to you problem might be L<autoupgrading|upgrading>.
+One solution to you problem might be autoupgrading|upgrading. See the
+pragmas L<bignum>, L<bigint> and L<bigrat> for an easy way to do this.
=item bsqrt()
C<bsqrt()> works only good if the result is a big integer, e.g. the square
root of 144 is 12, but from 12 the square root is 3, regardless of rounding
-mode.
+mode. The reason is that the result is always truncated to an integer.
If you want a better approximation of the square root, then use:
@@ -4345,8 +4532,11 @@ the same terms as Perl itself.
=head1 SEE ALSO
-L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
-L<Math::BigInt::Pari> and L<Math::BigInt::GMP>.
+L<Math::BigFloat>, L<Math::BigRat> and L<Math::Big> as well as
+L<Math::BigInt::BitVect>, L<Math::BigInt::Pari> and L<Math::BigInt::GMP>.
+
+The pragmas L<bignum>, L<bigint> and L<bigrat> also might be of interest
+because they solve the autoupgrading/downgrading issue, at least partly.
The package at
L<http://search.cpan.org/search?mode=module&query=Math%3A%3ABigInt> contains
@@ -4356,6 +4546,11 @@ subclass files and benchmarks.
=head1 AUTHORS
Original code by Mark Biggar, overloaded interface by Ilya Zakharevich.
-Completely rewritten by Tels http://bloodgate.com in late 2000, 2001.
+Completely rewritten by Tels http://bloodgate.com in late 2000, 2001, 2002
+and still at it in 2003.
+
+Many people contributed in one or more ways to the final beast, see the file
+CREDITS for an (uncomplete) list. If you miss your name, please drop me a
+mail. Thank you!
=cut