my $class = "Math::BigInt";
require 5.005;
-$VERSION = '1.68';
-use Exporter;
-@ISA = qw( Exporter );
-@EXPORT_OK = qw( objectify bgcd blcm);
+$VERSION = '1.77';
+
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(objectify bgcd blcm);
+
# _trap_inf and _trap_nan are internal and should never be accessed from the
# outside
use vars qw/$round_mode $accuracy $precision $div_scale $rnd_mode
'^=' => sub { $_[0]->bxor($_[1]); },
'&=' => sub { $_[0]->band($_[1]); },
'|=' => sub { $_[0]->bior($_[1]); },
+
'**=' => sub { $_[0]->bpow($_[1]); },
+'<<=' => sub { $_[0]->blsft($_[1]); },
+'>>=' => sub { $_[0]->brsft($_[1]); },
# not supported by Perl yet
'..' => \&_pointpoint,
+# we might need '==' and '!=' to get things like "NaN == NaN" right
'<=>' => sub { $_[2] ?
ref($_[0])->bcmp($_[1],$_[0]) :
- $_[0]->bcmp($_[1])},
+ $_[0]->bcmp($_[1]); },
'cmp' => sub {
$_[2] ?
"$_[1]" cmp $_[0]->bstr() :
'cos' => sub { cos($_[0]->numify()) },
'sin' => sub { sin($_[0]->numify()) },
'exp' => sub { exp($_[0]->numify()) },
-'atan2' => sub { atan2($_[0]->numify(),$_[1]) },
+'atan2' => sub { $_[2] ?
+ atan2($_[1],$_[0]->numify()) :
+ atan2($_[0]->numify(),$_[1]) },
+
+# are not yet overloadable
+#'hex' => sub { print "hex"; $_[0]; },
+#'oct' => sub { print "oct"; $_[0]; },
'log' => sub { $_[0]->copy()->blog($_[1]); },
'int' => sub { $_[0]->copy(); },
'sqrt' => sub { $_[0]->copy()->bsqrt(); },
'~' => sub { $_[0]->copy()->bnot(); },
-# for sub it is a bit tricky to keep b: b-a => -a+b
+# for subtract it's a bit tricky to not modify b: b-a => -a+b
'-' => sub { my $c = $_[0]->copy; $_[2] ?
- $c->bneg()->badd($_[1]) :
- $c->bsub( $_[1]) },
+ $c->bneg()->badd( $_[1]) :
+ $c->bsub( $_[1]) },
'+' => sub { $_[0]->copy()->badd($_[1]); },
'*' => sub { $_[0]->copy()->bmul($_[1]); },
'bool' => sub {
# this kludge is needed for perl prior 5.6.0 since returning 0 here fails :-/
# v5.6.1 dumps on this: return !$_[0]->is_zero() || undef; :-(
- my $t = !$_[0]->is_zero();
- undef $t if $t == 0;
+ my $t = undef;
+ $t = 1 if !$_[0]->is_zero();
$t;
},
##############################################################################
# global constants, flags and accessory
-# these are public, but their usage is not recommended, use the accessor
-# methods instead
+# These vars are public, but their direct usage is not recommended, use the
+# accessor methods instead
$round_mode = 'even'; # one of 'even', 'odd', '+inf', '-inf', 'zero' or 'trunc'
$accuracy = undef;
$upgrade = undef; # default is no upgrade
$downgrade = undef; # default is no downgrade
-# these are internally, and not to be used from the outside
-
-sub MB_NEVER_ROUND () { 0x0001; }
+# These are internally, and not to be used from the outside at all
$_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
- # default is Calc.pm
-my %CAN; # cache for $CALC->can(...)
+my $CALC = 'Math::BigInt::FastCalc'; # module to do the low level math
+ # default is FastCalc.pm
my $IMPORT = 0; # was import() called yet?
# used to make require work
-
+my %WARN; # warn only once for low-level libs
+my %CAN; # cache for $CALC->can(...)
+my %CALLBACKS; # callbacks to notify on lib loads
my $EMU_LIB = 'Math/BigInt/CalcEmu.pm'; # emulate low-level math
-my $EMU = 'Math::BigInt::CalcEmu'; # emulate low-level math
##############################################################################
# the old code had $rnd_mode, so we need to support it, too
# need to set new value?
if (@_ > 0)
{
- my $u = shift;
- return ${"${class}::upgrade"} = $u;
+ return ${"${class}::upgrade"} = $_[0];
}
${"${class}::upgrade"};
}
# need to set new value?
if (@_ > 0)
{
- my $u = shift;
- return ${"${class}::downgrade"} = $u;
+ return ${"${class}::downgrade"} = $_[0];
}
${"${class}::downgrade"};
}
{
require Carp; Carp::croak ('div_scale must be greater than zero');
}
- ${"${class}::div_scale"} = shift;
+ ${"${class}::div_scale"} = $_[0];
}
${"${class}::div_scale"};
}
if (ref($x))
{
# $object->accuracy() or fallback to global
- $x->bround($a) if $a; # not for undef, 0
- $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
+ delete $x->{_p}; # clear P
$a = ${"${class}::accuracy"} unless defined $a; # proper return value
}
else
{
- # set global
- ${"${class}::accuracy"} = $a;
- ${"${class}::precision"} = undef; # clear P
+ ${"${class}::accuracy"} = $a; # set global A
+ ${"${class}::precision"} = undef; # clear global P
}
- return $a; # shortcut
+ return $a; # shortcut
}
- my $r;
+ my $a;
# $object->accuracy() or fallback to global
- $r = $x->{_a} if ref($x);
+ $a = $x->{_a} if ref($x);
# but don't return global undef, when $x's accuracy is 0!
- $r = ${"${class}::accuracy"} if !defined $r;
- $r;
+ $a = ${"${class}::accuracy"} if !defined $a;
+ $a;
}
sub precision
if (ref($x))
{
# $object->precision() or fallback to global
- $x->bfround($p) if $p; # not for undef, 0
- $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
+ delete $x->{_a}; # clear A
$p = ${"${class}::precision"} unless defined $p; # proper return value
}
else
{
- # set global
- ${"${class}::precision"} = $p;
- ${"${class}::accuracy"} = undef; # clear A
+ ${"${class}::precision"} = $p; # set global P
+ ${"${class}::accuracy"} = undef; # clear global A
}
- return $p; # shortcut
+ return $p; # shortcut
}
- my $r;
+ my $p;
# $object->precision() or fallback to global
- $r = $x->{_p} if ref($x);
+ $p = $x->{_p} if ref($x);
# but don't return global undef, when $x's precision is 0!
- $r = ${"${class}::precision"} if !defined $r;
- $r;
+ $p = ${"${class}::precision"} if !defined $p;
+ $p;
}
sub config
{
# select accuracy parameter based on precedence,
# used by bround() and bfround(), may return undef for scale (means no op)
- my ($x,$s,$m,$scale,$mode) = @_;
- $scale = $x->{_a} if !defined $scale;
- $scale = $s if (!defined $scale);
- $mode = $m if !defined $mode;
- return ($scale,$mode);
+ my ($x,$scale,$mode) = @_;
+
+ $scale = $x->{_a} unless defined $scale;
+
+ no strict 'refs';
+ my $class = ref($x);
+
+ $scale = ${ $class . '::accuracy' } unless defined $scale;
+ $mode = ${ $class . '::round_mode' } unless defined $mode;
+
+ ($scale,$mode);
}
sub _scale_p
{
# select precision parameter based on precedence,
# used by bround() and bfround(), may return undef for scale (means no op)
- my ($x,$s,$m,$scale,$mode) = @_;
- $scale = $x->{_p} if !defined $scale;
- $scale = $s if (!defined $scale);
- $mode = $m if !defined $mode;
- return ($scale,$mode);
+ my ($x,$scale,$mode) = @_;
+
+ $scale = $x->{_p} unless defined $scale;
+
+ no strict 'refs';
+ my $class = ref($x);
+
+ $scale = ${ $class . '::precision' } unless defined $scale;
+ $mode = ${ $class . '::round_mode' } unless defined $mode;
+
+ ($scale,$mode);
}
##############################################################################
}
return unless ref($x); # only for objects
- my $self = {}; bless $self,$c;
- my $r;
- foreach my $k (keys %$x)
- {
- if ($k eq 'value')
- {
- $self->{value} = $CALC->_copy($x->{value}); next;
- }
- if (!($r = ref($x->{$k})))
- {
- $self->{$k} = $x->{$k}; next;
- }
- if ($r eq 'SCALAR')
- {
- $self->{$k} = \${$x->{$k}};
- }
- elsif ($r eq 'ARRAY')
- {
- $self->{$k} = [ @{$x->{$k}} ];
- }
- elsif ($r eq 'HASH')
- {
- # only one level deep!
- foreach my $h (keys %{$x->{$k}})
- {
- $self->{$k}->{$h} = $x->{$k}->{$h};
- }
- }
- else # normal ref
- {
- my $xk = $x->{$k};
- if ($xk->can('copy'))
- {
- $self->{$k} = $xk->copy();
- }
- else
- {
- $self->{$k} = $xk->new($xk);
- }
- }
- }
+ my $self = bless {}, $c;
+
+ $self->{sign} = $x->{sign};
+ $self->{value} = $CALC->_copy($x->{value});
+ $self->{_a} = $x->{_a} if defined $x->{_a};
+ $self->{_p} = $x->{_p} if defined $x->{_p};
$self;
}
if ((!ref $wanted) && ($wanted =~ /^([+-]?)[1-9][0-9]*\z/))
{
$self->{sign} = $1 || '+';
- my $ref = \$wanted;
+
if ($wanted =~ /^[+-]/)
{
# remove sign without touching wanted to make it work with constants
- my $t = $wanted; $t =~ s/^[+-]//; $ref = \$t;
+ my $t = $wanted; $t =~ s/^[+-]//;
+ $self->{value} = $CALC->_new($t);
+ }
+ else
+ {
+ $self->{value} = $CALC->_new($wanted);
}
- # 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)
|| (defined ${"${class}::precision"})
}
# handle '+inf', '-inf' first
- if ($wanted =~ /^[+-]?inf$/)
+ if ($wanted =~ /^[+-]?inf\z/)
{
- $self->{value} = $CALC->_zero();
- $self->{sign} = $wanted; $self->{sign} = '+inf' if $self->{sign} eq 'inf';
- return $self;
+ $self->{sign} = $wanted; # set a default sign for bstr()
+ return $self->binf($wanted);
}
# split str in m mantissa, e exponent, i integer, f fraction, v value, s sign
- my ($mis,$miv,$mfv,$es,$ev) = _split(\$wanted);
+ my ($mis,$miv,$mfv,$es,$ev) = _split($wanted);
if (!ref $mis)
{
if ($_trap_nan)
}
}
$self->{sign} = '+' if $$miv eq '0'; # normalize -0 => +0
- $self->{value} = $CALC->_new($miv) if $self->{sign} =~ /^[+-]$/;
+ $self->{value} = $CALC->_new($$miv) if $self->{sign} =~ /^[+-]$/;
# if any of the globals is set, use them to round and store them inside $self
# do not round for new($x,undef,undef) since that is used by MBF to signal
# no rounding
}
$self->{sign} = $nan;
delete $self->{_a}; delete $self->{_p}; # rounding NaN is silly
- return $self;
+ $self;
}
sub binf
if (${"${class}::_trap_inf"})
{
require Carp;
- Carp::croak ("Tried to set $self to +-inf in $class\::binfn()");
+ Carp::croak ("Tried to set $self to +-inf in $class\::binf()");
}
$self->import() if $IMPORT == 0; # make require work
return if $self->modify('binf');
$sign = $sign . 'inf' if $sign !~ /inf$/; # - => -inf
$self->{sign} = $sign;
($self->{_a},$self->{_p}) = @_; # take over requested rounding
- return $self;
+ $self;
}
sub bzero
{
# create a bigint '+0', if given a BigInt, set it to 0
my $self = shift;
- $self = $class if !defined $self;
+ $self = __PACKAGE__ if !defined $self;
if (!ref($self))
{
sub bone
{
# create a bigint '+1' (or -1 if given sign '-'),
- # if given a BigInt, set it to +1 or -1, respecively
+ # if given a BigInt, set it to +1 or -1, respectively
my $self = shift;
my $sign = shift; $sign = '+' if !defined $sign || $sign ne '-';
$self = $class if !defined $self;
# (ref to BFLOAT or num_str ) return num_str
# Convert number from internal format to scientific string format.
# internal format is always normalized (no leading zeros, "-0E0" => "+0E0")
- my $x = shift; $class = ref($x) || $x; $x = $class->new(shift) if !ref($x);
- # my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+ my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
if ($x->{sign} !~ /^[+-]$/)
{
my ($m,$e) = $x->parts();
#$m->bstr() . 'e+' . $e->bstr(); # e can only be positive in BigInt
# 'e+' because E can only be positive in BigInt
- $m->bstr() . 'e+' . ${$CALC->_str($e->{value})};
+ $m->bstr() . 'e+' . $CALC->_str($e->{value});
}
sub bstr
{
# make a string from bigint object
- my $x = shift; $class = ref($x) || $x; $x = $class->new(shift) if !ref($x);
- # my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+ my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
if ($x->{sign} !~ /^[+-]$/)
{
return 'inf'; # +inf
}
my $es = ''; $es = $x->{sign} if $x->{sign} eq '-';
- $es.${$CALC->_str($x->{value})};
+ $es.$CALC->_str($x->{value});
}
sub numify
# $r round_mode, if given by caller
# @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;
-
my $c = ref($self); # find out class of argument(s)
no strict 'refs';
# $r round_mode, if given by caller
# @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;
-
my $c = ref($self); # find out class of argument(s)
no strict 'refs';
{
$self->bfround($p,$r) if !defined $self->{_p} || $self->{_p} <= $p;
}
- $self->bnorm(); # after round, normalize
+ # bround() or bfround() already callled bnorm() if necc.
+ $self;
}
sub bnorm
{
# (BINT or num_str) return BINT
# make number absolute, or return absolute BINT from string
- my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+ my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
return $x if $x->modify('babs');
# post-normalized abs for internal use (does nothing for NaN)
{
# (BINT or num_str) return BINT
# negate number or make a negated number from string
- my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+ my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
return $x if $x->modify('bneg');
- # for +0 dont negate (to have always normalized)
- $x->{sign} =~ tr/+-/-+/ if !$x->is_zero(); # does nothing for NaN
+ # for +0 dont negate (to have always normalized +0). Does nothing for 'NaN'
+ $x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $CALC->_is_zero($x->{value}));
$x;
}
# 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; # inf is always bigger
+ return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
+ return -1;
}
$CALC->_acmp($x->{value},$y->{value}); # lib does only 0,1,-1
}
$x->{value} = $CALC->_sub($x->{value}, $y->{value}); # abs sub
}
}
- $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
- $x;
+ $x->round(@r);
}
sub bsub
return $x if $x->modify('bsub');
-# upgrade done by badd():
-# return $upgrade->badd($x,$y,@r) if defined $upgrade &&
-# ((!$x->isa($self)) || (!$y->isa($self)));
+ return $upgrade->new($x)->bsub($upgrade->new($y),@r) if defined $upgrade &&
+ ((!$x->isa($self)) || (!$y->isa($self)));
- if ($y->is_zero())
- {
- $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
- return $x;
- }
+ return $x->round(@r) if $y->is_zero();
+ # To correctly handle the lone special case $x->bsub($x), we note the sign
+ # of $x, then flip the sign from $y, and if the sign of $x did change, too,
+ # then we caught the special case:
+ my $xsign = $x->{sign};
$y->{sign} =~ tr/+\-/-+/; # does nothing for NaN
+ if ($xsign ne $x->{sign})
+ {
+ # special case of $x->bsub($x) results in 0
+ return $x->bzero(@r) if $xsign =~ /^[+-]$/;
+ return $x->bnan(); # NaN, -inf, +inf
+ }
$x->badd($y,@r); # badd does not leave internal zeros
$y->{sign} =~ tr/+\-/-+/; # refix $y (does nothing for NaN)
$x; # already rounded by badd() or no round necc.
if ($x->{sign} eq '+')
{
$x->{value} = $CALC->_inc($x->{value});
- $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
- return $x;
+ return $x->round($a,$p,$r);
}
elsif ($x->{sign} eq '-')
{
$x->{value} = $CALC->_dec($x->{value});
$x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0
- $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
- return $x;
+ return $x->round($a,$p,$r);
}
# inf, nan handling etc
$x->badd($self->bone(),$a,$p,$r); # badd does round
if ($x->{sign} eq '-')
{
- # < 0
+ # x already < 0
$x->{value} = $CALC->_inc($x->{value});
}
else
{
- return $x->badd($self->bone('-'),@r) unless $x->{sign} eq '+'; # inf/NaN
+ return $x->badd($self->bone('-'),@r) unless $x->{sign} eq '+'; # inf or NaN
# >= 0
if ($CALC->_is_zero($x->{value}))
{
$x->{value} = $CALC->_dec($x->{value});
}
}
- $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
- $x;
+ $x->round(@r);
}
sub blog
# $base of $x)
# set up parameters
- my ($self,$x,$base,@r) = (ref($_[0]),@_);
+ my ($self,$x,$base,@r) = (undef,@_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
- ($self,$x,$base,@r) = objectify(2,$class,@_);
+ ($self,$x,$base,@r) = objectify(1,ref($x),@_);
}
+
+ return $x if $x->modify('blog');
# inf, -inf, NaN, <0 => NaN
return $x->bnan()
- if $x->{sign} ne '+' || $base->{sign} ne '+';
-
- return $upgrade->blog($upgrade->new($x),$base,@r) if
- defined $upgrade && (ref($x) ne $upgrade || ref($base) ne $upgrade);
+ if $x->{sign} ne '+' || (defined $base && $base->{sign} ne '+');
- if ($CAN{log_int})
- {
- my ($rc,$exact) = $CALC->_log_int($x->{value},$base->{value});
- return $x->bnan() unless defined $rc;
- $x->{value} = $rc;
- return $x->round(@r);
- }
+ return $upgrade->blog($upgrade->new($x),$base,@r) if
+ defined $upgrade;
- require $EMU_LIB;
- __emu_blog($self,$x,$base,@r);
+ my ($rc,$exact) = $CALC->_log_int($x->{value},$base->{value});
+ return $x->bnan() unless defined $rc; # not possible to take log?
+ $x->{value} = $rc;
+ $x->round(@r);
}
sub blcm
{
$x = $class->new($y);
}
- while (@_) { $x = __lcm($x,shift); }
+ my $self = ref($x);
+ while (@_)
+ {
+ my $y = shift; $y = $self->new($y) if !ref ($y);
+ $x = __lcm($x,$y);
+ }
$x;
}
# GCD -- Euclids algorithm, variant C (Knuth Vol 3, pg 341 ff)
my $y = shift;
- $y = __PACKAGE__->new($y) if !ref($y);
+ $y = $class->new($y) if !ref($y);
my $self = ref($y);
- my $x = $y->copy(); # keep arguments
- if ($CAN{gcd})
- {
- while (@_)
- {
- $y = shift; $y = $self->new($y) if !ref($y);
- next if $y->is_zero();
- return $x->bnan() if $y->{sign} !~ /^[+-]$/; # y NaN?
- $x->{value} = $CALC->_gcd($x->{value},$y->{value}); last if $x->is_one();
- }
- }
- else
+ my $x = $y->copy()->babs(); # keep arguments
+ return $x->bnan() if $x->{sign} !~ /^[+-]$/; # x NaN?
+
+ while (@_)
{
- while (@_)
- {
- $y = shift; $y = $self->new($y) if !ref($y);
- $x = __gcd($x,$y->copy()); last if $x->is_one(); # _gcd handles NaN
- }
+ $y = shift; $y = $self->new($y) if !ref($y);
+ return $x->bnan() if $y->{sign} !~ /^[+-]$/; # y NaN?
+ $x->{value} = $CALC->_gcd($x->{value},$y->{value});
+ last if $CALC->_is_one($x->{value});
}
- $x->babs();
+ $x;
}
sub bnot
{
# return true when arg (BINT or num_str) is positive (>= 0)
my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
-
- $x->{sign} =~ /^\+/ ? 1 : 0; # +inf is also positive, but NaN not
+
+ return 1 if $x->{sign} eq '+inf'; # +inf is positive
+
+ # 0+ is neither positive nor negative
+ ($x->{sign} eq '+' && !$x->is_zero()) ? 1 : 0;
}
sub is_negative
# return true when arg (BINT or num_str) is negative (< 0)
my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
- $x->{sign} =~ /^-/ ? 1 : 0; # -inf is also negative, but NaN not
+ $x->{sign} =~ /^-/ ? 1 : 0; # -inf is negative, but NaN is not
}
sub is_int
return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
return $x->binf('-');
}
-
- return $upgrade->bmul($x,$y,@r)
- if defined $upgrade && $y->isa($upgrade);
+
+ return $upgrade->bmul($x,$upgrade->new($y),@r)
+ if defined $upgrade && !$y->isa($self);
$r[3] = $y; # no push here
$x->{value} = $CALC->_mul($x->{value},$y->{value}); # do actual math
$x->{sign} = '+' if $CALC->_is_zero($x->{value}); # no -0
- $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
- $x;
+ $x->round(@r);
}
sub _div_inf
$x->{sign} = '+' if $CALC->_is_zero($x->{value});
$rem->{_a} = $x->{_a};
$rem->{_p} = $x->{_p};
- $x->round(@r) if !exists $x->{_f} || ($x->{_f} & MB_NEVER_ROUND) == 0;
+ $x->round(@r);
if (! $CALC->_is_zero($rem->{value}))
{
$rem->{sign} = $y->{sign};
{
$rem->{sign} = '+'; # dont leave -0
}
- $rem->round(@r) if !exists $rem->{_f} || ($rem->{_f} & MB_NEVER_ROUND) == 0;
+ $rem->round(@r);
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;
+ $x->round(@r);
}
###############################################################################
return $x->round(@r);
}
- if ($CAN{mod})
+ # calc new sign and in case $y == +/- 1, return $x
+ $x->{value} = $CALC->_mod($x->{value},$y->{value});
+ if (!$CALC->_is_zero($x->{value}))
{
- # calc new sign and in case $y == +/- 1, return $x
- $x->{value} = $CALC->_mod($x->{value},$y->{value});
- if (!$CALC->_is_zero($x->{value}))
- {
- my $xsign = $x->{sign};
- $x->{sign} = $y->{sign};
- if ($xsign ne $y->{sign})
- {
- my $t = $CALC->_copy($x->{value}); # copy $x
- $x->{value} = $CALC->_sub($y->{value},$t,1); # $y-$x
- }
- }
- else
- {
- $x->{sign} = '+'; # dont leave -0
- }
- $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
- return $x;
+ $x->{value} = $CALC->_sub($y->{value},$x->{value},1) # $y-$x
+ if ($x->{sign} ne $y->{sign});
+ $x->{sign} = $y->{sign};
}
- # disable upgrade temporarily, otherwise endless loop due to bdiv()
- local $upgrade = undef;
- my ($t,$rem) = $self->bdiv($x->copy(),$y,@r); # slow way (also rounds)
- # modify in place
- foreach (qw/value sign _a _p/)
+ else
{
- $x->{$_} = $rem->{$_};
+ $x->{sign} = '+'; # dont leave -0
}
- $x;
+ $x->round(@r);
}
sub bmodinv
# (i.e. their gcd is not one) then NaN is returned.
# set up parameters
- my ($self,$x,$y,@r) = (ref($_[0]),@_);
+ my ($self,$x,$y,@r) = (undef,@_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
# put least residue into $x if $x was negative, and thus make it positive
$x->bmod($y) if $x->{sign} eq '-';
- if ($CAN{modinv})
- {
- my $sign;
- ($x->{value},$sign) = $CALC->_modinv($x->{value},$y->{value});
- return $x->bnan() if !defined $x->{value}; # in case no GCD found
- return $x if !defined $sign; # already real result
- $x->{sign} = $sign; # flip/flop see below
- $x->bmod($y); # calc real result
- return $x;
- }
-
- require $EMU_LIB;
- __emu_bmodinv($self,$x,$y,@r);
+ my $sign;
+ ($x->{value},$sign) = $CALC->_modinv($x->{value},$y->{value});
+ return $x->bnan() if !defined $x->{value}; # in case no GCD found
+ return $x if !defined $sign; # already real result
+ $x->{sign} = $sign; # flip/flop see below
+ $x->bmod($y); # calc real result
+ $x;
}
sub bmodpow
# check num for valid values (also NaN if there was no inverse but $exp < 0)
return $num->bnan() if $num->{sign} !~ /^[+-]$/;
- if ($CAN{modpow})
- {
- # $mod is positive, sign on $exp is ignored, result also positive
- $num->{value} = $CALC->_modpow($num->{value},$exp->{value},$mod->{value});
- return $num;
- }
-
- require $EMU_LIB;
- __emu_bmodpow($self,$num,$exp,$mod,@r);
+ # $mod is positive, sign on $exp is ignored, result also positive
+ $num->{value} = $CALC->_modpow($num->{value},$exp->{value},$mod->{value});
+ $num;
}
###############################################################################
{
# (BINT or num_str, BINT or num_str) return BINT
# compute factorial number from $x, modify $x in place
- my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
-
- return $x if $x->modify('bfac');
-
- return $x if $x->{sign} eq '+inf'; # inf => inf
- return $x->bnan() if $x->{sign} ne '+'; # NaN, <0 etc => NaN
+ my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_);
- if ($CAN{fac})
- {
- $x->{value} = $CALC->_fac($x->{value});
- return $x->round(@r);
- }
+ return $x if $x->modify('bfac') || $x->{sign} eq '+inf'; # inf => inf
+ return $x->bnan() if $x->{sign} ne '+'; # NaN, <0 etc => NaN
- require $EMU_LIB;
- __emu_bfac($self,$x,@r);
+ $x->{value} = $CALC->_fac($x->{value});
+ $x->round(@r);
}
sub bpow
return $x if $x->modify('bpow');
+ return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
+
+ # inf handling
+ if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
+ {
+ if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/))
+ {
+ # +-inf ** +-inf
+ return $x->bnan();
+ }
+ # +-inf ** Y
+ if ($x->{sign} =~ /^[+-]inf/)
+ {
+ # +inf ** 0 => NaN
+ return $x->bnan() if $y->is_zero();
+ # -inf ** -1 => 1/inf => 0
+ return $x->bzero() if $y->is_one('-') && $x->is_negative();
+
+ # +inf ** Y => inf
+ return $x if $x->{sign} eq '+inf';
+
+ # -inf ** Y => -inf if Y is odd
+ return $x if $y->is_odd();
+ return $x->babs();
+ }
+ # X ** +-inf
+
+ # 1 ** +inf => 1
+ return $x if $x->is_one();
+
+ # 0 ** inf => 0
+ return $x if $x->is_zero() && $y->{sign} =~ /^[+]/;
+
+ # 0 ** -inf => inf
+ return $x->binf() if $x->is_zero();
+
+ # -1 ** -inf => NaN
+ return $x->bnan() if $x->is_one('-') && $y->{sign} =~ /^[-]/;
+
+ # -X ** -inf => 0
+ return $x->bzero() if $x->{sign} eq '-' && $y->{sign} =~ /^[-]/;
+
+ # -1 ** inf => NaN
+ return $x->bnan() if $x->{sign} eq '-';
+
+ # X ** inf => inf
+ return $x->binf() if $y->{sign} =~ /^[+]/;
+ # X ** -inf => 0
+ return $x->bzero();
+ }
+
return $upgrade->bpow($upgrade->new($x),$y,@r)
if defined $upgrade && !$y->isa($self);
$r[3] = $y; # no push!
- return $x if $x->{sign} =~ /^[+-]inf$/; # -inf/+inf ** x
- return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
# cases 0 ** Y, X ** 0, X ** 1, 1 ** Y are handled by Calc or Emu
- if ($x->{sign} eq '-' && $CALC->_is_one($x->{value}))
- {
- # if $x == -1 and odd/even y => +1/-1
- return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
- # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
- }
+ my $new_sign = '+';
+ $new_sign = $y->is_odd() ? '-' : '+' if ($x->{sign} ne '+');
+
+ # 0 ** -7 => ( 1 / (0 ** 7)) => 1 / 0 => +inf
+ return $x->binf()
+ if $y->{sign} eq '-' && $x->{sign} eq '+' && $CALC->_is_zero($x->{value});
# 1 ** -y => 1 / (1 ** |y|)
# so do test for negative $y after above's clause
- return $x->bnan() if $y->{sign} eq '-' && !$x->is_one();
+ return $x->bnan() if $y->{sign} eq '-' && !$CALC->_is_one($x->{value});
- if ($CAN{pow})
- {
- $x->{value} = $CALC->_pow($x->{value},$y->{value});
- $x->{sign} = '+' if $CALC->_is_zero($y->{value});
- $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
- return $x;
- }
-
- require $EMU_LIB;
- __emu_bpow($self,$x,$y,@r);
+ $x->{value} = $CALC->_pow($x->{value},$y->{value});
+ $x->{sign} = $new_sign;
+ $x->{sign} = '+' if $CALC->_is_zero($y->{value});
+ $x->round(@r);
}
sub blsft
$n = 2 if !defined $n; return $x->bnan() if $n <= 0 || $y->{sign} eq '-';
- my $t; $t = $CALC->_lsft($x->{value},$y->{value},$n) if $CAN{lsft};
- if (defined $t)
- {
- $x->{value} = $t; return $x->round(@r);
- }
- # fallback
- $x->bmul( $self->bpow($n, $y, @r), @r );
+ $x->{value} = $CALC->_lsft($x->{value},$y->{value},$n);
+ $x->round(@r);
}
sub brsft
$x->bdec(); # n == 2, but $y == 1: this fixes it
}
- my $t; $t = $CALC->_rsft($x->{value},$y->{value},$n) if $CAN{rsft};
- if (defined $t)
- {
- $x->{value} = $t;
- return $x->round(@r);
- }
- # fallback
- $x->bdiv($self->bpow($n,$y, @r), @r);
- $x;
+ $x->{value} = $CALC->_rsft($x->{value},$y->{value},$n);
+ $x->round(@r);
}
sub band
my $sx = $x->{sign} eq '+' ? 1 : -1;
my $sy = $y->{sign} eq '+' ? 1 : -1;
- if ($CAN{and} && $sx == 1 && $sy == 1)
+ if ($sx == 1 && $sy == 1)
{
$x->{value} = $CALC->_and($x->{value},$y->{value});
return $x->round(@r);
return $x if $x->modify('bior');
$r[3] = $y; # no push!
- local $Math::BigInt::upgrade = undef;
-
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
my $sx = $x->{sign} eq '+' ? 1 : -1;
# the sign of X follows the sign of X, e.g. sign of Y irrelevant for bior()
# don't use lib for negative values
- if ($CAN{or} && $sx == 1 && $sy == 1)
+ if ($sx == 1 && $sy == 1)
{
$x->{value} = $CALC->_or($x->{value},$y->{value});
return $x->round(@r);
my $sy = $y->{sign} eq '+' ? 1 : -1;
# don't use lib for negative values
- if ($CAN{xor} && $sx == 1 && $sy == 1)
+ if ($sx == 1 && $sy == 1)
{
$x->{value} = $CALC->_xor($x->{value},$y->{value});
return $x->round(@r);
sub digit
{
# return the nth decimal digit, negative values count backward, 0 is right
- my ($self,$x,$n) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+ my ($self,$x,$n) = ref($_[0]) ? (undef,@_) : objectify(1,@_);
+ $n = $n->numify() if ref($n);
$CALC->_digit($x->{value},$n||0);
}
my $x = shift;
$x = $class->new($x) unless ref $x;
- return 0 if $x->is_zero() || $x->is_odd() || $x->{sign} !~ /^[+-]$/;
+ return 0 if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf etc
- return $CALC->_zeros($x->{value}) if $CAN{zeros};
-
- # if not: since we do not know underlying internal representation:
- my $es = "$x"; $es =~ /([0]*)$/;
- return 0 if !defined $1; # no zeros
- CORE::length("$1"); # as string, not as +0!
+ $CALC->_zeros($x->{value}); # must handle odd values, 0 etc
}
sub bsqrt
{
# calculate square root of $x
- my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+ my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_);
return $x if $x->modify('bsqrt');
return $upgrade->bsqrt($x,@r) if defined $upgrade;
- if ($CAN{sqrt})
- {
- $x->{value} = $CALC->_sqrt($x->{value});
- return $x->round(@r);
- }
-
- require $EMU_LIB;
- __emu_bsqrt($self,$x,@r);
+ $x->{value} = $CALC->_sqrt($x->{value});
+ $x->round(@r);
}
sub broot
# objectify is costly, so avoid it
if ((!ref($x)) || (ref($x) ne ref($y)))
{
- ($self,$x,$y,@r) = $self->objectify(2,@_);
+ ($self,$x,$y,@r) = objectify(2,$self || $class,@_);
}
return $x if $x->modify('broot');
return $upgrade->new($x)->broot($upgrade->new($y),@r) if defined $upgrade;
- if ($CAN{root})
- {
- $x->{value} = $CALC->_root($x->{value},$y->{value});
- return $x->round(@r);
- }
-
- require $EMU_LIB;
- __emu_broot($self,$x,$y,@r);
+ $x->{value} = $CALC->_root($x->{value},$y->{value});
+ $x->round(@r);
}
sub exponent
{
# precision: round to the $Nth digit left (+$n) or right (-$n) from the '.'
# $n == 0 || $n == 1 => round to integer
- my $x = shift; $x = $class->new($x) unless ref $x;
+ my $x = shift; my $self = ref($x) || $x; $x = $self->new($x) unless ref $x;
- my ($scale,$mode) = $x->_scale_p($x->precision(),$x->round_mode(),@_);
+ my ($scale,$mode) = $x->_scale_p(@_);
return $x if !defined $scale || $x->modify('bfround'); # no-op
# no-op for BigInts if $n <= 0
$x->bround( $x->length()-$scale, $mode) if $scale > 0;
- $x->{_a} = undef; # bround sets {_a}
- $x->{_p} = $scale; # so correct it
+ delete $x->{_a}; # delete to save memory
+ $x->{_p} = $scale; # store new _p
$x;
}
sub _scan_for_nonzero
{
- # internal, used by bround()
- my ($x,$pad,$xs) = @_;
+ # internal, used by bround() to scan for non-zeros after a '5'
+ my ($x,$pad,$xs,$len) = @_;
- my $len = $x->length();
- return 0 if $len == 1; # '5' is trailed by invisible zeros
+ return 0 if $len == 1; # "5" is trailed by invisible zeros
my $follow = $pad - 1;
return 0 if $follow > $len || $follow < 1;
- # since we do not know underlying represention of $x, use decimal string
- my $r = substr ("$x",-$follow);
- $r =~ /[^0]/ ? 1 : 0;
+ # use the string form to check whether only '0's follow or not
+ substr ($xs,-$follow) =~ /[^0]/ ? 1 : 0;
}
sub fround
{
# Exists to make life easier for switch between MBF and MBI (should we
# autoload fxxx() like MBF does for bxxx()?)
- my $x = shift;
+ my $x = shift; $x = $class->new($x) unless ref $x;
$x->bround(@_);
}
# do not return $x->bnorm(), but $x
my $x = shift; $x = $class->new($x) unless ref $x;
- my ($scale,$mode) = $x->_scale_a($x->accuracy(),$x->round_mode(),@_);
- return $x if !defined $scale; # no-op
- return $x if $x->modify('bround');
+ my ($scale,$mode) = $x->_scale_a(@_);
+ return $x if !defined $scale || $x->modify('bround'); # no-op
if ($x->is_zero() || $scale == 0)
{
$pad = $len - $scale;
$pad = abs($scale-1) if $scale < 0;
- # do not use digit(), it is costly for binary => decimal
-
+ # do not use digit(), it is very costly for binary => decimal
+ # getting the entire string is also costly, but we need to do it only once
my $xs = $CALC->_str($x->{value});
my $pl = -$pad-1;
# pad: 123: 0 => -1, at 1 => -2, at 2 => -3, at 3 => -4
# pad+1: 123: 0 => 0, at 1 => -1, at 2 => -2, at 3 => -3
- $digit_round = '0'; $digit_round = substr($$xs,$pl,1) if $pad <= $len;
+ $digit_round = '0'; $digit_round = substr($xs,$pl,1) if $pad <= $len;
$pl++; $pl ++ if $pad >= $len;
- $digit_after = '0'; $digit_after = substr($$xs,$pl,1) if $pad > 0;
+ $digit_after = '0'; $digit_after = substr($xs,$pl,1) if $pad > 0;
# in case of 01234 we round down, for 6789 up, and only in case 5 we look
# closer at the remaining digits of the original $x, remember decision
($digit_after =~ /[01234]/) || # round down anyway,
# 6789 => round up
($digit_after eq '5') && # not 5000...0000
- ($x->_scan_for_nonzero($pad,$xs) == 0) &&
+ ($x->_scan_for_nonzero($pad,$xs,$len) == 0) &&
(
($mode eq 'even') && ($digit_round =~ /[24680]/) ||
($mode eq 'odd') && ($digit_round =~ /[13579]/) ||
if (($pad > 0) && ($pad <= $len))
{
- substr($$xs,-$pad,$pad) = '0' x $pad;
- $put_back = 1;
+ substr($xs,-$pad,$pad) = '0' x $pad; # replace with '00...'
+ $put_back = 1; # need to put back
}
elsif ($pad > $len)
{
if ($round_up) # what gave test above?
{
- $put_back = 1;
- $pad = $len, $$xs = '0' x $pad if $scale < 0; # tlr: whack 0.51=>1.0
+ $put_back = 1; # need to put back
+ $pad = $len, $xs = '0' x $pad if $scale < 0; # tlr: whack 0.51=>1.0
# we modify directly the string variant instead of creating a number and
# adding it, since that is faster (we already have the string)
my $c = 0; $pad ++; # for $pad == $len case
while ($pad <= $len)
{
- $c = substr($$xs,-$pad,1) + 1; $c = '0' if $c eq '10';
- substr($$xs,-$pad,1) = $c; $pad++;
+ $c = substr($xs,-$pad,1) + 1; $c = '0' if $c eq '10';
+ substr($xs,-$pad,1) = $c; $pad++;
last if $c != 0; # no overflow => early out
}
- $$xs = '1'.$$xs if $c == 0;
+ $xs = '1'.$xs if $c == 0;
}
- $x->{value} = $CALC->_new($xs) if $put_back == 1; # put back in if needed
+ $x->{value} = $CALC->_new($xs) if $put_back == 1; # put back, if needed
$x->{_a} = $scale if $scale >= 0;
if ($scale < 0)
my $s = '';
$s = $x->{sign} if $x->{sign} eq '-';
- if ($CAN{as_hex})
- {
- return $s . ${$CALC->_as_hex($x->{value})};
- }
-
- require $EMU_LIB;
- __emu_as_hex(ref($x),$x,$s);
+ $s . $CALC->_as_hex($x->{value});
}
sub as_bin
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
my $s = ''; $s = $x->{sign} if $x->{sign} eq '-';
- if ($CAN{as_bin})
- {
- return $s . ${$CALC->_as_bin($x->{value})};
- }
-
- require $EMU_LIB;
- __emu_as_bin(ref($x),$x,$s);
-
+ return $s . $CALC->_as_bin($x->{value});
}
##############################################################################
# the first argument is number of args objectify() should look at it will
# return $count+1 elements, the first will be a classname. This is because
# overloaded '""' calls bstr($object,undef,undef) and this would result in
- # useless objects beeing created and thrown away. So we cannot simple loop
+ # useless objects being created and thrown away. So we cannot simple loop
# over @_. If the given count is 0, all arguments will be used.
# If the second arg is a ref, use it as class.
@a;
}
+sub _register_callback
+ {
+ my ($class,$callback) = @_;
+
+ if (ref($callback) ne 'CODE')
+ {
+ require Carp;
+ Carp::croak ("$callback is not a coderef");
+ }
+ $CALLBACKS{$class} = $callback;
+ }
+
sub import
{
my $self = shift;
}
}
# any non :constant stuff is handled by our parent, Exporter
- # even if @_ is empty, to give it a chance
- $self->SUPER::import(@a); # need it for subclasses
- $self->export_to_level(1,$self,@a); # need it for MBF
+ if (@a > 0)
+ {
+ require Exporter;
+
+ $self->SUPER::import(@a); # need it for subclasses
+ $self->export_to_level(1,$self,@a); # need it for MBF
+ }
# try to load core math lib
my @c = split /\s*,\s*/,$CALC;
- push @c,'Calc'; # if all fail, try this
+ foreach (@c)
+ {
+ $_ =~ tr/a-zA-Z0-9://cd; # limit to sane characters
+ }
+ push @c, 'FastCalc', 'Calc'; # if all fail, try these
$CALC = ''; # signal error
foreach my $lib (@c)
{
$lib =~ s/\.pm$//;
if ($] < 5.006)
{
- # Perl < 5.6.0 dies with "out of memory!" when eval() and ':constant' is
- # used in the same script, or eval inside import().
+ # Perl < 5.6.0 dies with "out of memory!" when eval("") and ':constant' is
+ # used in the same script, or eval("") inside import().
my @parts = split /::/, $lib; # Math::BigInt => Math BigInt
my $file = pop @parts; $file .= '.pm'; # BigInt => BigInt.pm
require File::Spec;
{
eval "use $lib qw/@c/;";
}
- $CALC = $lib, last if $@ eq ''; # no error in loading lib?
+ if ($@ eq '')
+ {
+ my $ok = 1;
+ # loaded it ok, see if the api_version() is high enough
+ if ($lib->can('api_version') && $lib->api_version() >= 1.0)
+ {
+ $ok = 0;
+ # api_version matches, check if it really provides anything we need
+ for my $method (qw/
+ one two ten
+ str num
+ add mul div sub dec inc
+ acmp len digit is_one is_zero is_even is_odd
+ is_two is_ten
+ new copy check from_hex from_bin as_hex as_bin zeros
+ rsft lsft xor and or
+ mod sqrt root fac pow modinv modpow log_int gcd
+ /)
+ {
+ if (!$lib->can("_$method"))
+ {
+ if (($WARN{$lib}||0) < 2)
+ {
+ require Carp;
+ Carp::carp ("$lib is missing method '_$method'");
+ $WARN{$lib} = 1; # still warn about the lib
+ }
+ $ok++; last;
+ }
+ }
+ }
+ if ($ok == 0)
+ {
+ $CALC = $lib;
+ last; # found a usable one, break
+ }
+ else
+ {
+ if (($WARN{$lib}||0) < 2)
+ {
+ my $ver = eval "\$$lib\::VERSION" || 'unknown';
+ require Carp;
+ Carp::carp ("Cannot load outdated $lib v$ver, please upgrade");
+ $WARN{$lib} = 2; # never warn again
+ }
+ }
+ }
}
if ($CALC eq '')
{
require Carp;
Carp::croak ("Couldn't load any math lib, not even 'Calc.pm'");
}
- _fill_can_cache();
- }
-sub _fill_can_cache
- {
- # fill $CAN with the results of $CALC->can(...)
+ # notify callbacks
+ foreach my $class (keys %CALLBACKS)
+ {
+ &{$CALLBACKS{$class}}($CALC);
+ }
+
+ # Fill $CAN with the results of $CALC->can(...) for emulating lower math lib
+ # functions
%CAN = ();
- for my $method (qw/gcd mod modinv modpow fac pow lsft rsft
- and signed_and or signed_or xor signed_xor
- from_hex as_hex from_bin as_bin
- zeros sqrt root log_int log
- /)
+ for my $method (qw/ signed_and signed_or signed_xor /)
{
$CAN{$method} = $CALC->can("_$method") ? 1 : 0;
}
+
+ # import done
}
sub __from_hex
{
+ # internal
# convert a (ref to) big hex string to BigInt, return undef for error
my $hs = shift;
my $x = Math::BigInt->bzero();
# strip underscores
- $$hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g;
- $$hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g;
+ $hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g;
+ $hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g;
- return $x->bnan() if $$hs !~ /^[\-\+]?0x[0-9A-Fa-f]+$/;
+ return $x->bnan() if $hs !~ /^[\-\+]?0x[0-9A-Fa-f]+$/;
- my $sign = '+'; $sign = '-' if ($$hs =~ /^-/);
+ my $sign = '+'; $sign = '-' if $hs =~ /^-/;
- $$hs =~ s/^[+-]//; # strip sign
- if ($CAN{'from_hex'})
- {
- $x->{value} = $CALC->_from_hex($hs);
- }
- else
- {
- # fallback to pure perl
- my $mul = Math::BigInt->bone();
- my $x65536 = Math::BigInt->new(65536);
- my $len = CORE::length($$hs)-2; # minus 2 for 0x
- $len = int($len/4); # 4-digit parts, w/o '0x'
- my $val; my $i = -4;
- while ($len >= 0)
- {
- $val = substr($$hs,$i,4);
- $val =~ s/^[+-]?0x// if $len == 0; # for last part only because
- $val = hex($val); # hex does not like wrong chars
- $i -= 4; $len --;
- $x += $mul * $val if $val != 0;
- $mul *= $x65536 if $len >= 0; # skip last mul
- }
- }
+ $hs =~ s/^[+-]//; # strip sign
+ $x->{value} = $CALC->_from_hex($hs);
$x->{sign} = $sign unless $CALC->_is_zero($x->{value}); # no '-0'
$x;
}
sub __from_bin
{
+ # internal
# convert a (ref to) big binary string to BigInt, return undef for error
my $bs = shift;
my $x = Math::BigInt->bzero();
# strip underscores
- $$bs =~ s/([01])_([01])/$1$2/g;
- $$bs =~ s/([01])_([01])/$1$2/g;
- return $x->bnan() if $$bs !~ /^[+-]?0b[01]+$/;
+ $bs =~ s/([01])_([01])/$1$2/g;
+ $bs =~ s/([01])_([01])/$1$2/g;
+ return $x->bnan() if $bs !~ /^[+-]?0b[01]+$/;
- my $sign = '+'; $sign = '-' if ($$bs =~ /^\-/);
- $$bs =~ s/^[+-]//; # strip sign
- if ($CAN{'from_bin'})
- {
- $x->{value} = $CALC->_from_bin($bs);
- }
- else
- {
- my $mul = Math::BigInt->bone();
- my $x256 = Math::BigInt->new(256);
- my $len = CORE::length($$bs)-2; # minus 2 for 0b
- $len = int($len/8); # 8-digit parts, w/o '0b'
- my $val; my $i = -8;
- while ($len >= 0)
- {
- $val = substr($$bs,$i,8);
- $val =~ s/^[+-]?0b// if $len == 0; # for last part only
- #$val = oct('0b'.$val); # does not work on Perl prior to 5.6.0
- # slower:
- # $val = ('0' x (8-CORE::length($val))).$val if CORE::length($val) < 8;
- $val = ord(pack('B8',substr('00000000'.$val,-8,8)));
- $i -= 8; $len --;
- $x += $mul * $val if $val != 0;
- $mul *= $x256 if $len >= 0; # skip last mul
- }
- }
+ my $sign = '+'; $sign = '-' if $bs =~ /^\-/;
+ $bs =~ s/^[+-]//; # strip sign
+
+ $x->{value} = $CALC->_from_bin($bs);
$x->{sign} = $sign unless $CALC->_is_zero($x->{value}); # no '-0'
$x;
}
sub _split
{
- # (ref to num_str) return num_str
- # internal, take apart a string and return the pieces
- # strip leading/trailing whitespace, leading zeros, underscore and reject
- # invalid input
+ # input: num_str; output: undef for invalid or
+ # (\$mantissa_sign,\$mantissa_value,\$mantissa_fraction,\$exp_sign,\$exp_value)
+ # Internal, take apart a string and return the pieces.
+ # Strip leading/trailing whitespace, leading zeros, underscore and reject
+ # invalid input.
my $x = shift;
# strip white space at front, also extranous leading zeros
- $$x =~ s/^\s*([-]?)0*([0-9])/$1$2/g; # will not strip ' .2'
- $$x =~ s/^\s+//; # but this will
- $$x =~ s/\s+$//g; # strip white space at end
+ $x =~ s/^\s*([-]?)0*([0-9])/$1$2/g; # will not strip ' .2'
+ $x =~ s/^\s+//; # but this will
+ $x =~ s/\s+$//g; # strip white space at end
# shortcut, if nothing to split, return early
- if ($$x =~ /^[+-]?\d+\z/)
+ if ($x =~ /^[+-]?\d+\z/)
{
- $$x =~ s/^([+-])0*([0-9])/$2/; my $sign = $1 || '+';
- return (\$sign, $x, \'', \'', \0);
+ $x =~ s/^([+-])0*([0-9])/$2/; my $sign = $1 || '+';
+ return (\$sign, \$x, \'', \'', \0);
}
# invalid starting char?
- return if $$x !~ /^[+-]?(\.?[0-9]|0b[0-1]|0x[0-9a-fA-F])/;
+ return if $x !~ /^[+-]?(\.?[0-9]|0b[0-1]|0x[0-9a-fA-F])/;
- return __from_hex($x) if $$x =~ /^[\-\+]?0x/; # hex string
- return __from_bin($x) if $$x =~ /^[\-\+]?0b/; # binary string
+ return __from_hex($x) if $x =~ /^[\-\+]?0x/; # hex string
+ return __from_bin($x) if $x =~ /^[\-\+]?0b/; # binary string
# strip underscores between digits
- $$x =~ s/(\d)_(\d)/$1$2/g;
- $$x =~ s/(\d)_(\d)/$1$2/g; # do twice for 1_2_3
+ $x =~ s/(\d)_(\d)/$1$2/g;
+ $x =~ s/(\d)_(\d)/$1$2/g; # do twice for 1_2_3
# some possible inputs:
# 2.1234 # 0.12 # 1 # 1E1 # 2.134E1 # 434E-10 # 1.02009E-2
# .2 # 1_2_3.4_5_6 # 1.4E1_2_3 # 1e3 # +.2 # 0e999
- #return if $$x =~ /[Ee].*[Ee]/; # more than one E => error
-
- my ($m,$e,$last) = split /[Ee]/,$$x;
+ my ($m,$e,$last) = split /[Ee]/,$x;
return if defined $last; # last defined => 1e2E3 or others
$e = '0' if !defined $e || $e eq "";
# does modify first argument
# LCM
- my $x = shift; my $ty = shift;
- return $x->bnan() if ($x->{sign} eq $nan) || ($ty->{sign} eq $nan);
- return $x * $ty / bgcd($x,$ty);
- }
-
-sub __gcd
- {
- # (BINT or num_str, BINT or num_str) return BINT
- # does modify both arguments
- # GCD -- Euclids algorithm E, Knuth Vol 2 pg 296
my ($x,$ty) = @_;
-
- return $x->bnan() if $x->{sign} !~ /^[+-]$/ || $ty->{sign} !~ /^[+-]$/;
-
- while (!$ty->is_zero())
- {
- ($x, $ty) = ($ty,bmod($x,$ty));
- }
- $x;
+ return $x->bnan() if ($x->{sign} eq $nan) || ($ty->{sign} eq $nan);
+ my $method = ref($x) . '::bgcd';
+ no strict 'refs';
+ $x * $ty / &$method($x,$ty);
}
###############################################################################
-# this method return 0 if the object can be modified, or 1 for not
+# this method returns 0 if the object can be modified, or 1 if not.
# We use a fast constant sub() here, to avoid costly calls. Subclasses
# may override it with special code (f.i. Math::BigInt::Constant does so)
1;
__END__
+=pod
+
=head1 NAME
-Math::BigInt - Arbitrary size integer math package
+Math::BigInt - Arbitrary size integer/float math package
=head1 SYNOPSIS
use Math::BigInt lib => 'GMP';
+ my $str = '1234567890';
+ my @values = (64,74,18);
+ my $n = 1; my $sign = '-';
+
# Number creation
$x = Math::BigInt->new($str); # defaults to 0
+ $y = $x->copy(); # make a true copy
$nan = Math::BigInt->bnan(); # create a NotANumber
$zero = Math::BigInt->bzero(); # create a +0
$inf = Math::BigInt->binf(); # create a +inf
$x->is_even(); # if $x is even
$x->is_pos(); # if $x >= 0
$x->is_neg(); # if $x < 0
- $x->is_inf(sign); # if $x is +inf, or -inf (sign is default '+')
+ $x->is_inf($sign); # if $x is +inf, or -inf (sign is default '+')
$x->is_int(); # if $x is an integer (not a float)
- # comparing and digit/sign extration
+ # comparing and digit/sign extraction
$x->bcmp($y); # compare numbers (undef,<0,=0,>0)
$x->bacmp($y); # compare absolutely (undef,<0,=0,>0)
$x->sign(); # return the sign, either +,- or NaN
# 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.
+ # necessary when mixing $a = $b assignments with non-overloaded math.
$x->bzero(); # set $x to 0
$x->bnan(); # set $x to NaN
$x->bfac(); # factorial of $x (1*2*3*4*..$x)
$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
+ $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 (are no-ops),
# but do so in BigFloat:
# The following do not modify their arguments:
- bgcd(@values); # greatest common divisor (no OO style)
- blcm(@values); # lowest common multiplicator (no OO style)
+ # greatest common divisor (no OO style)
+ my $gcd = Math::BigInt::bgcd(@values);
+ # lowest common multiplicator (no OO style)
+ my $lcm = Math::BigInt::blcm(@values);
$x->length(); # return number of digits in number
- ($x,$f) = $x->length(); # length of number and length of fraction part,
- # latter is always 0 digits long for BigInt's
+ ($xl,$f) = $x->length(); # length of number and length of fraction part,
+ # latter is always 0 digits long for BigInts
$x->exponent(); # return exponent as BigInt
$x->mantissa(); # return (signed) mantissa as BigInt
$x->numify(); # return as scalar (might overflow!)
# conversation to string (do not modify their argument)
- $x->bstr(); # normalized string
- $x->bsstr(); # normalized string in scientific notation
+ $x->bstr(); # normalized string (e.g. '3')
+ $x->bsstr(); # norm. string in scientific notation (e.g. '3E0')
$x->as_hex(); # as signed hexadecimal string with prefixed 0x
$x->as_bin(); # as signed binary string with prefixed 0b
$x->accuracy($n); # set A $x to $n
# Global methods
- Math::BigInt->precision(); # get/set global P for all BigInt objects
- Math::BigInt->accuracy(); # get/set global A for all BigInt objects
- Math::BigInt->config(); # return hash containing configuration
+ Math::BigInt->precision(); # get/set global P for all BigInt objects
+ Math::BigInt->accuracy(); # get/set global A for all BigInt objects
+ Math::BigInt->round_mode(); # get/set global round mode, one of
+ # 'even', 'odd', '+inf', '-inf', 'zero' or 'trunc'
+ Math::BigInt->config(); # return hash containing configuration
=head1 DESCRIPTION
-All operators (inlcuding basic math operations) are overloaded if you
+All operators (including basic math operations) are overloaded if you
declare your big integers as
$i = new Math::BigInt '123_456_789_123_456_789';
=item Output
-Output values are BigInt objects (normalized), except for bstr(), which
-returns a string in normalized form.
+Output values are BigInt objects (normalized), except for the methods which
+return a string (see L<SYNOPSIS>).
+
Some routines (C<is_odd()>, C<is_even()>, C<is_zero()>, C<is_one()>,
-C<is_nan()>) return true or false, while others (C<bcmp()>, C<bacmp()>)
-return either undef, <0, 0 or >0 and are suited for sort.
+C<is_nan()>, etc.) return true or false, while others (C<bcmp()>, C<bacmp()>)
+return either undef (if NaN is involved), <0, 0 or >0 and are suited for sort.
=back
=head1 METHODS
Each of the methods below (except config(), accuracy() and precision())
-accepts three additional parameters. These arguments $A, $P and $R are
-accuracy, precision and round_mode. Please see the section about
+accepts three additional parameters. These arguments C<$A>, C<$P> and C<$R>
+are C<accuracy>, C<precision> and C<round_mode>. Please see the section about
L<ACCURACY and PRECISION> for more information.
=head2 config
even
version version number of the class you used
1.61
- div_scale Fallback acccuracy for div
+ div_scale Fallback accuracy for div
40
trap_nan If true, traps creation of NaN via croak()
1
$x->accuracy(5); # local for $x
CLASS->accuracy(5); # global for all members of CLASS
- $A = $x->accuracy(); # read out
- $A = CLASS->accuracy(); # read out
+ # Note: This also applies to new()!
+
+ $A = $x->accuracy(); # read out accuracy that affects $x
+ $A = CLASS->accuracy(); # read out global accuracy
Set or get the global or local accuracy, aka how many significant digits the
-results have.
+results have. If you set a global accuracy, then this also applies to new()!
+
+Warning! The accuracy I<sticks>, e.g. once you created a number under the
+influence of C<< CLASS->accuracy($A) >>, all results from math operations with
+that number will also be rounded.
+
+In most cases, you should probably round the results explicitly using one of
+L<round()>, L<bround()> or L<bfround()> or by passing the desired accuracy
+to the math operation as additional parameter:
+
+ my $x = Math::BigInt->new(30000);
+ my $y = Math::BigInt->new(7);
+ print scalar $x->copy()->bdiv($y, 2); # print 4300
+ print scalar $x->copy()->bdiv($y)->bround(2); # print 4300
Please see the section about L<ACCURACY AND PRECISION> for further details.
$y = Math::BigInt->new(1234567); # unrounded
print Math::BigInt->accuracy(4),"\n"; # set 4, print 4
- $x = Math::BigInt->new(123456); # will be automatically rounded
+ $x = Math::BigInt->new(123456); # $x will be automatically rounded!
print "$x $y\n"; # '123500 1234567'
print $x->accuracy(),"\n"; # will be 4
print $y->accuracy(),"\n"; # also 4, since global is 4
=head2 precision
- $x->precision(-2); # local for $x, round right of the dot
- $x->precision(2); # ditto, but round left of the dot
- CLASS->accuracy(5); # global for all members of CLASS
- CLASS->precision(-5); # ditto
- $P = CLASS->precision(); # read out
- $P = $x->precision(); # read out
+ $x->precision(-2); # local for $x, round at the second digit right of the dot
+ $x->precision(2); # ditto, round at the second digit left of the dot
-Set or get the global or local precision, aka how many digits the result has
-after the dot (or where to round it when passing a positive number). In
-Math::BigInt, passing a negative number precision has no effect since no
-numbers have digits after the dot.
+ CLASS->precision(5); # Global for all members of CLASS
+ # This also applies to new()!
+ CLASS->precision(-5); # ditto
+
+ $P = CLASS->precision(); # read out global precision
+ $P = $x->precision(); # read out precision that affects $x
+
+Note: You probably want to use L<accuracy()> instead. With L<accuracy> you
+set the number of digits each result should have, with L<precision> you
+set the place where to round!
+
+C<precision()> sets or gets the global or local precision, aka at which digit
+before or after the dot to round all results. A set global precision also
+applies to all newly created numbers!
+
+In Math::BigInt, passing a negative number precision has no effect since no
+numbers have digits after the dot. In L<Math::BigFloat>, it will round all
+results to P digits after the dot.
Please see the section about L<ACCURACY AND PRECISION> for further details.
-Value must be greater than zero. Pass an undef value to disable it:
+Pass an undef value to disable it:
$x->precision(undef);
Math::BigInt->precision(undef);
Returns the current precision. For C<$x->precision()> it will return either the
local precision of $x, or if not defined, the global. This means the return
-value represents the accuracy that will be in effect for $x:
+value represents the prevision that will be in effect for $x:
$y = Math::BigInt->new(1234567); # unrounded
print Math::BigInt->precision(4),"\n"; # set 4, print 4
$x = Math::BigInt->new(123456); # will be automatically rounded
+ print $x; # print "120000"!
-Note: Works also for subclasses like Math::BigFloat. Each class has it's own
-globals separated from Math::BigInt, but it is possible to subclass
+Note: Works also for subclasses like L<Math::BigFloat>. Each class has its
+own globals separated from Math::BigInt, but it is possible to subclass
Math::BigInt and make the globals of the subclass aliases to the ones from
Math::BigInt.
$x->is_inf(); # true if +inf
$x->is_inf('-'); # true if -inf (sign is default '+')
-These methods all test the BigInt for beeing one specific value and return
+These methods all test the BigInt for being one specific value and return
true or false depending on the input. These are faster than doing something
like:
=head2 is_pos()/is_neg()
- $x->is_pos(); # true if >= 0
- $x->is_neg(); # true if < 0
+ $x->is_pos(); # true if > 0
+ $x->is_neg(); # true if < 0
The methods return true if the argument is positive or negative, respectively.
C<NaN> is neither positive nor negative, while C<+inf> counts as positive, and
-C<-inf> is negative. A C<zero> is positive.
+C<-inf> is negative. A C<zero> is neither positive nor negative.
These methods are only testing the sign, and not the value.
-C<is_positive()> and C<is_negative()> are aliase to C<is_pos()> and
+C<is_positive()> and C<is_negative()> are aliases to C<is_pos()> and
C<is_neg()>, respectively. C<is_positive()> and C<is_negative()> were
introduced in v1.36, while C<is_pos()> and C<is_neg()> were only introduced
in v1.68.
Return the sign, of $x, meaning either C<+>, C<->, C<-inf>, C<+inf> or NaN.
+If you want $x to have a certain sign, use one of the following methods:
+
+ $x->babs(); # '+'
+ $x->babs()->bneg(); # '-'
+ $x->bnan(); # 'NaN'
+ $x->binf(); # '+inf'
+ $x->binf('-'); # '-inf'
+
=head2 digit
$x->digit($n); # return the nth digit, counting from right
$x->bstr();
-Returns a normalized string represantation of C<$x>.
+Returns a normalized string representation of C<$x>.
=head2 bsstr
result has at most max(scale, length(dividend), length(divisor)) digits
Actual code:
scale = max(scale, length(dividend)-1,length(divisor)-1);
- scale += length(divisior) - length(dividend);
+ scale += length(divisor) - length(dividend);
So for lx = 3, ly = 9, scale = 10, scale will actually be 16 (10+9-3).
Actually, the 'difference' added to the scale is calculated from the
number of "significant digits" in dividend and divisor, which is derived
* to find out the current global P, use C<< Math::SomeClass->precision() >>
* use C<< $x->accuracy() >> respective C<< $x->precision() >> for the local
setting of C<< $x >>.
- * Please note that C<< $x->accuracy() >> respecive C<< $x->precision() >>
+ * Please note that C<< $x->accuracy() >> respective C<< $x->precision() >>
return eventually defined global A or P, when C<< $x >>'s A or P is not
set.
be automatically cleared.
* If two objects are involved in an operation, and one of them has A in
effect, and the other P, this results in an error (NaN).
- * A takes precendence over P (Hint: A comes before P).
+ * A takes precedence over P (Hint: A comes before P).
If neither of them is defined, nothing is used, i.e. the result will have
as many digits as it can (with an exception for fdiv/fsqrt) and will not
be rounded.
+ never round (this is the default):
This is done by setting A and P to undef. No math operation
will round the result, with fdiv() and fsqrt() as exceptions to guard
- against overflows. You must explicitely call bround(), bfround() or
+ against overflows. You must explicitly call bround(), bfround() or
round() (the latter with parameters).
Note: Once you have rounded a number, the settings will 'stick' on it
and 'infect' all other numbers engaged in math operations with it, since
=back
+=head1 Infinity and Not a Number
+
+While BigInt has extensive handling of inf and NaN, certain quirks remain.
+
+=over 2
+
+=item oct()/hex()
+
+These perl routines currently (as of Perl v.5.8.6) cannot handle passed
+inf.
+
+ te@linux:~> perl -wle 'print 2 ** 3333'
+ inf
+ te@linux:~> perl -wle 'print 2 ** 3333 == 2 ** 3333'
+ 1
+ te@linux:~> perl -wle 'print oct(2 ** 3333)'
+ 0
+ te@linux:~> perl -wle 'print hex(2 ** 3333)'
+ Illegal hexadecimal digit 'i' ignored at -e line 1.
+ 0
+
+The same problems occur if you pass them Math::BigInt->binf() objects. Since
+overloading these routines is not possible, this cannot be fixed from BigInt.
+
+=item ==, !=, <, >, <=, >= with NaNs
+
+BigInt's bcmp() routine currently returns undef to signal that a NaN was
+involved in a comparison. However, the overload code turns that into
+either 1 or '' and thus operations like C<< NaN != NaN >> might return
+wrong values.
+
+=item log(-inf)
+
+C<< log(-inf) >> is highly weird. Since log(-x)=pi*i+log(x), then
+log(-inf)=pi*i+inf. However, since the imaginary part is finite, the real
+infinity "overshadows" it, so the number might as well just be infinity.
+However, the result is a complex number, and since BigInt/BigFloat can only
+have real numbers as results, the result is NaN.
+
+=item exp(), cos(), sin(), atan2()
+
+These all might have problems handling infinity right.
+
+=back
+
=head1 INTERNALS
The actual numbers are stored as unsigned big integers (with seperate sign).
+
You should neither care about nor depend on the internal representation; it
-might change without notice. Use only method calls like C<< $x->sign(); >>
-instead relying on the internal hash keys like in C<< $x->{sign}; >>.
+might change without notice. Use B<ONLY> method calls like C<< $x->sign(); >>
+instead relying on the internal representation.
=head2 MATH LIBRARY
use Math::BigInt lib => 'Foo,Math::BigInt::Bar';
Since Math::BigInt::GMP is in almost all cases faster than Calc (especially in
-cases involving really big numbers, where it is B<much> faster), and there is
+math involving really big numbers, where it is B<much> faster), and there is
no penalty if Math::BigInt::GMP is not installed, it is a good idea to always
use the following:
use Math::BigInt lib => 'GMP';
Different low-level libraries use different formats to store the
-numbers. You should not depend on the number having a specific format.
+numbers. You should B<NOT> depend on the number having a specific format
+internally.
See the respective math library module documentation for further details.
=head2 SIGN
-The sign is either '+', '-', 'NaN', '+inf' or '-inf' and stored seperately.
+The sign is either '+', '-', 'NaN', '+inf' or '-inf'.
A sign of 'NaN' is used to represent the result when input arguments are not
numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively
With a technique called copy-on-write, the cost of copying with overload could
be minimized or even completely avoided. A test implementation of COW did show
performance gains for overloaded math, but introduced a performance loss due
-to a constant overhead for all other operatons. So Math::BigInt does currently
+to a constant overhead for all other operations. So Math::BigInt does currently
not COW.
The rewritten version of this module (vs. v0.01) is slower on certain
There is now a C<bsstr()> method to get the string in scientific notation aka
C<1e+2> instead of C<100>. Be advised that overloaded 'eq' always uses bstr()
-for comparisation, but Perl will represent some numbers as 100 and others
+for comparison, but Perl will represent some numbers as 100 and others
as 1e+308. If in doubt, convert both arguments to Math::BigInt before
comparing them as strings:
$y = Math::BigInt->new($y);
ok ($x,$y); # okay
-Alternatively, simple use C<< <=> >> for comparisations, this will get it
+Alternatively, simple use C<< <=> >> for comparisons, this will get it
always right. There is not yet a way to get a number automatically represented
as a string that matches exactly the way Perl represents it.
+See also the section about L<Infinity and Not a Number> for problems in
+comparing NaNs.
+
=item int()
C<int()> will return (at least for Perl v5.7.1 and up) another BigInt, not a
$x = Math::BigFloat->new(123.45);
$y = int($x); # BigInt 123
-In all Perl versions you can use C<as_number()> for the same effect:
+In all Perl versions you can use C<as_number()> or C<as_int> for the same
+effect:
$x = Math::BigFloat->new(123.45);
$y = $x->as_number(); # BigInt 123
+ $y = $x->as_int(); # ditto
This also works for other subclasses, like Math::String.
-It is yet unlcear whether overloaded int() should return a scalar or a BigInt.
+It is yet unclear whether overloaded int() should return a scalar or a BigInt.
+
+If you want a real Perl scalar, use C<numify()>:
+
+ $y = $x->numify(); # 123 as scalar
+
+This is seldom necessary, though, because this is done automatically, like
+when you access an array:
+
+ $z = $array[$x]; # does work automatically
=item length
print $c->bdiv(10000),"\n";
It prints both quotient and remainder since print calls C<bdiv()> in list
-context. Also, C<bdiv()> will modify $c, so be carefull. You probably want
+context. Also, C<bdiv()> will modify $c, so be careful. You probably want
to use
print $c / 10000,"\n";
holds true for any $x and $y, which justifies calling the two return
values of bdiv() the quotient and remainder. The only exception to this rule
are when $y == 0 and $x is negative, then the remainder will also be
-negative. See below under "infinity handling" for the reasoning behing this.
+negative. See below under "infinity handling" for the reasoning behind this.
Perl's 'use integer;' changes the behaviour of % and / for scalars, but will
not change BigInt's way to do things. This is because under 'use integer' Perl
needs to preserve $x since it does not know that it later will get overwritten.
This makes a copy of $x and takes O(N), but $x->bneg() is O(1).
-With Copy-On-Write, this issue would be gone, but C-o-W is not implemented
-since it is slower for all other things.
-
=item Mixing different object types
In Perl you will get a floating point value if you do one of the following:
=head1 AUTHORS
Original code by Mark Biggar, overloaded interface by Ilya Zakharevich.
-Completely rewritten by Tels http://bloodgate.com in late 2000, 2001, 2002
-and still at it in 2003.
+Completely rewritten by Tels http://bloodgate.com in late 2000, 2001 - 2004
+and still at it in 2005.
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
+CREDITS for an (incomplete) list. If you miss your name, please drop me a
mail. Thank you!
=cut