+package Math::BigInt;
+
+#
+# "Mike had an infinite amount to do and a negative amount of time in which
+# to do it." - Before and After
+#
+
# The following hash values are used:
# value: unsigned int with actual value (as a Math::BigInt::Calc or similiar)
# sign : +,-,NaN,+inf,-inf
# Remember not to take shortcuts ala $xs = $x->{value}; $CALC->foo($xs); since
# underlying lib might change the reference!
-package Math::BigInt;
my $class = "Math::BigInt";
require 5.005;
-$VERSION = '1.51';
+$VERSION = '1.64_01';
use Exporter;
@ISA = qw( Exporter );
@EXPORT_OK = qw( objectify _swap bgcd blcm);
'<=>' => sub { $_[2] ?
ref($_[0])->bcmp($_[1],$_[0]) :
- ref($_[0])->bcmp($_[0],$_[1])},
+ $_[0]->bcmp($_[1])},
'cmp' => sub {
$_[2] ?
"$_[1]" cmp $_[0]->bstr() :
sub upgrade
{
no strict 'refs';
- # make Class->round_mode() work
+ # make Class->upgrade() work
my $self = shift;
my $class = ref($self) || $self || __PACKAGE__;
- if (defined $_[0])
+ # need to set new value?
+ if (@_ > 0)
{
my $u = shift;
return ${"${class}::upgrade"} = $u;
return ${"${class}::upgrade"};
}
+sub downgrade
+ {
+ no strict 'refs';
+ # make Class->downgrade() work
+ my $self = shift;
+ my $class = ref($self) || $self || __PACKAGE__;
+ # need to set new value?
+ if (@_ > 0)
+ {
+ my $u = shift;
+ return ${"${class}::downgrade"} = $u;
+ }
+ return ${"${class}::downgrade"};
+ }
+
sub div_scale
{
no strict 'refs';
return $a; # shortcut
}
- if (ref($x))
- {
- # $object->accuracy() or fallback to global
- return $x->{_a} || ${"${class}::accuracy"};
- }
- return ${"${class}::accuracy"};
+ my $r;
+ # $object->accuracy() or fallback to global
+ $r = $x->{_a} if ref($x);
+ # but don't return global undef, when $x's accuracy is 0!
+ $r = ${"${class}::accuracy"} if !defined $r;
+ $r;
}
sub precision
return $p; # shortcut
}
- if (ref($x))
- {
- # $object->precision() or fallback to global
- return $x->{_p} || ${"${class}::precision"};
- }
- return ${"${class}::precision"};
+ my $r;
+ # $object->precision() or fallback to global
+ $r = $x->{_p} if ref($x);
+ # but don't return global undef, when $x's precision is 0!
+ $r = ${"${class}::precision"} if !defined $r;
+ $r;
}
sub config
class => $class,
};
foreach (
- qw/upgrade downgrade precisison accuracy round_mode VERSION div_scale/)
+ qw/upgrade downgrade precision accuracy round_mode VERSION div_scale/)
{
$cfg->{lc($_)} = ${"${class}::$_"};
};
# avoid numify-calls by not using || on $wanted!
return $class->bzero($a,$p) if !defined $wanted; # default to 0
- return $class->copy($wanted,$a,$p,$r) if ref($wanted);
+ return $class->copy($wanted,$a,$p,$r)
+ if ref($wanted) && $wanted->isa($class); # MBI or subclass
$class->import() if $IMPORT == 0; # make require work
- my $self = {}; bless $self, $class;
+ my $self = bless {}, $class;
+
+ # shortcut for "normal" numbers
+ 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;
+ }
+ $self->{value} = $CALC->_new($ref);
+ no strict 'refs';
+ if ( (defined $a) || (defined $p)
+ || (defined ${"${class}::precision"})
+ || (defined ${"${class}::accuracy"})
+ )
+ {
+ $self->round($a,$p,$r) unless (@_ == 4 && !defined $a && !defined $p);
+ }
+ return $self;
+ }
+
# handle '+inf', '-inf' first
if ($wanted =~ /^[+-]?inf$/)
{
# do not round for new($x,undef,undef) since that is used by MBF to signal
# no rounding
$self->round($a,$p,$r) unless @_ == 4 && !defined $a && !defined $p;
- # print "mbi new $self\n";
- return $self;
+ $self;
}
sub bnan
}
$self->import() if $IMPORT == 0; # make require work
return if $self->modify('bnan');
- $self->{value} = $CALC->_zero();
+ my $c = ref($self);
+ if ($self->can('_bnan'))
+ {
+ # use subclass to initialize
+ $self->_bnan();
+ }
+ else
+ {
+ # otherwise do our own thing
+ $self->{value} = $CALC->_zero();
+ }
$self->{sign} = $nan;
delete $self->{_a}; delete $self->{_p}; # rounding NaN is silly
return $self;
# create a bigint '+-inf', if given a BigInt, set it to '+-inf'
# the sign is either '+', or if given, used from there
my $self = shift;
- my $sign = shift; $sign = '+' if !defined $sign || $sign ne '-';
+ my $sign = shift; $sign = '+' if !defined $sign || $sign !~ /^-(inf)?$/;
$self = $class if !defined $self;
if (!ref($self))
{
}
$self->import() if $IMPORT == 0; # make require work
return if $self->modify('binf');
- $self->{value} = $CALC->_zero();
- $self->{sign} = $sign.'inf';
+ my $c = ref($self);
+ if ($self->can('_binf'))
+ {
+ # use subclass to initialize
+ $self->_binf();
+ }
+ else
+ {
+ # otherwise do our own thing
+ $self->{value} = $CALC->_zero();
+ }
+ $sign = $sign . 'inf' if $sign !~ /inf$/; # - => -inf
+ $self->{sign} = $sign;
($self->{_a},$self->{_p}) = @_; # take over requested rounding
return $self;
}
}
$self->import() if $IMPORT == 0; # make require work
return if $self->modify('bzero');
- $self->{value} = $CALC->_zero();
+
+ if ($self->can('_bzero'))
+ {
+ # use subclass to initialize
+ $self->_bzero();
+ }
+ else
+ {
+ # otherwise do our own thing
+ $self->{value} = $CALC->_zero();
+ }
$self->{sign} = '+';
if (@_ > 0)
{
- $self->{_a} = $_[0]
- if (defined $self->{_a} && defined $_[0] && $_[0] > $self->{_a});
- $self->{_p} = $_[1]
- if (defined $self->{_p} && defined $_[1] && $_[1] < $self->{_p});
+ if (@_ > 3)
+ {
+ # call like: $x->bzero($a,$p,$r,$y);
+ ($self,$self->{_a},$self->{_p}) = $self->_find_round_parameters(@_);
+ }
+ else
+ {
+ $self->{_a} = $_[0]
+ if ( (!defined $self->{_a}) || (defined $_[0] && $_[0] > $self->{_a}));
+ $self->{_p} = $_[1]
+ if ( (!defined $self->{_p}) || (defined $_[1] && $_[1] > $self->{_p}));
+ }
}
- return $self;
+ $self;
}
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;
}
$self->import() if $IMPORT == 0; # make require work
return if $self->modify('bone');
- $self->{value} = $CALC->_one();
+
+ if ($self->can('_bone'))
+ {
+ # use subclass to initialize
+ $self->_bone();
+ }
+ else
+ {
+ # otherwise do our own thing
+ $self->{value} = $CALC->_one();
+ }
$self->{sign} = $sign;
if (@_ > 0)
{
- $self->{_a} = $_[0]
- if (defined $self->{_a} && defined $_[0] && $_[0] > $self->{_a});
- $self->{_p} = $_[1]
- if (defined $self->{_p} && defined $_[1] && $_[1] < $self->{_p});
+ if (@_ > 3)
+ {
+ # call like: $x->bone($sign,$a,$p,$r,$y);
+ ($self,$self->{_a},$self->{_p}) = $self->_find_round_parameters(@_);
+ }
+ else
+ {
+ $self->{_a} = $_[0]
+ if ( (!defined $self->{_a}) || (defined $_[0] && $_[0] > $self->{_a}));
+ $self->{_p} = $_[1]
+ if ( (!defined $self->{_p}) || (defined $_[1] && $_[1] > $self->{_p}));
+ }
}
- return $self;
+ $self;
}
##############################################################################
return 'inf'; # +inf
}
my ($m,$e) = $x->parts();
- # e can only be positive
- my $sign = 'e+';
- # MBF: my $s = $e->{sign}; $s = '' if $s eq '-'; my $sep = 'e'.$s;
+ my $sign = 'e+'; # e can only be positive
return $m->bstr().$sign.$e->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,@_);
-
+
if ($x->{sign} !~ /^[+-]$/)
{
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
{
# Make a "normal" scalar from a BigInt object
my $x = shift; $x = $class->new($x) unless ref $x;
- return $x->{sign} if $x->{sign} !~ /^[+-]$/;
+
+ return $x->bstr() if $x->{sign} !~ /^[+-]$/;
my $num = $CALC->_num($x->{value});
return -$num if $x->{sign} eq '-';
- return $num;
+ $num;
}
##############################################################################
sub sign
{
- # return the sign of the number: +/-/NaN
+ # return the sign of the number: +/-/-inf/+inf/NaN
my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
- return $x->{sign};
+ $x->{sign};
}
sub _find_round_parameters
{
# Compares 2 values. Returns one of undef, <0, =0, >0. (suitable for sort)
# (BINT or num_str, BINT or num_str) return cond_code
- my ($self,$x,$y) = objectify(2,@_);
+
+ # set up parameters
+ my ($self,$x,$y) = (ref($_[0]),@_);
+
+ # objectify is costly, so avoid it
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+ {
+ ($self,$x,$y) = objectify(2,@_);
+ }
+
+ return $upgrade->bcmp($x,$y) if defined $upgrade &&
+ ((!$x->isa($self)) || (!$y->isa($self)));
if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
{
return 1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # does also 0 <=> -y
return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # does also -x <=> 0
- # shortcut
- my $xz = $x->is_zero();
- my $yz = $y->is_zero();
- return 0 if $xz && $yz; # 0 <=> 0
- return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y
- return 1 if $yz && $x->{sign} eq '+'; # +x <=> 0
-
+ # have same sign, so compare absolute values. Don't make tests for zero here
+ # because it's actually slower than testin in Calc (especially w/ Pari et al)
+
# post-normalized compare for internal use (honors signs)
if ($x->{sign} eq '+')
{
- return 1 if $y->{sign} eq '-'; # 0 check handled above
+ # $x and $y both > 0
return $CALC->_acmp($x->{value},$y->{value});
}
- # $x->{sign} eq '-'
- return -1 if $y->{sign} eq '+';
- $CALC->_acmp($y->{value},$x->{value}); # swaped (lib does only 0,1,-1)
+ # $x && $y both < 0
+ $CALC->_acmp($y->{value},$x->{value}); # swaped (lib returns 0,1,-1)
}
sub bacmp
# Compares 2 values, ignoring their signs.
# Returns one of undef, <0, =0, >0. (suitable for sort)
# (BINT, BINT) return cond_code
- my ($self,$x,$y) = objectify(2,@_);
+ # set up parameters
+ my ($self,$x,$y) = (ref($_[0]),@_);
+ # objectify is costly, so avoid it
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+ {
+ ($self,$x,$y) = objectify(2,@_);
+ }
+
+ return $upgrade->bacmp($x,$y) if defined $upgrade &&
+ ((!$x->isa($self)) || (!$y->isa($self)));
+
if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
{
# handle +-inf and NaN
{
# add second arg (BINT or string) to first (BINT) (modifies first)
# return result as BINT
- my ($self,$x,$y,@r) = objectify(2,@_);
+
+ # 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('badd');
-# print "mbi badd ",join(' ',caller()),"\n";
-# print "upgrade => ",$upgrade||'undef',
-# " \$x (",ref($x),") \$y (",ref($y),")\n";
-# return $upgrade->badd($x,$y,@r) if defined $upgrade &&
-# ((ref($x) eq $upgrade) || (ref($y) eq $upgrade));
-# print "still badd\n";
+ return $upgrade->badd($x,$y,@r) if defined $upgrade &&
+ ((!$x->isa($self)) || (!$y->isa($self)));
$r[3] = $y; # no push!
# inf and NaN handling
{
# NaN first
return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
- # inf handline
- if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/))
+ # inf handling
+ if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/))
{
# +inf++inf or -inf+-inf => same, rest is NaN
return $x if $x->{sign} eq $y->{sign};
$x->{sign} = $sx;
}
}
- $x->round(@r);
+ $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ $x;
}
sub bsub
{
# (BINT or num_str, BINT or num_str) return num_str
# subtract second arg from first, modify first
- my ($self,$x,$y,@r) = objectify(2,@_);
+
+ # 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('bsub');
+
+# upgrade done by badd():
# return $upgrade->badd($x,$y,@r) if defined $upgrade &&
-# ((ref($x) eq $upgrade) || (ref($y) eq $upgrade));
+# ((!$x->isa($self)) || (!$y->isa($self)));
if ($y->is_zero())
{
- return $x->round(@r);
+ $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ return $x;
}
$y->{sign} =~ tr/+\-/-+/; # does nothing for NaN
if ($x->{sign} eq '+')
{
$x->{value} = $CALC->_inc($x->{value});
- return $x->round($a,$p,$r);
+ $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ return $x;
}
elsif ($x->{sign} eq '-')
{
$x->{value} = $CALC->_dec($x->{value});
$x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0
- return $x->round($a,$p,$r);
+ $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ return $x;
}
# inf, nan handling etc
$x->badd($self->__one(),$a,$p,$r); # badd does round
$x->{value} = $CALC->_inc($x->{value});
$x->{sign} = '-' if $zero; # 0 => 1 => -1
$x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0
- return $x->round($a,$p,$r);
+ $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ return $x;
}
# > 0
elsif ($x->{sign} eq '+')
{
$x->{value} = $CALC->_dec($x->{value});
- return $x->round($a,$p,$r);
+ $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ return $x;
}
# inf, nan handling etc
$x->badd($self->__one('-'),$a,$p,$r); # badd does round
my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
return 1 if $x->{sign} eq $nan;
- return 0;
+ 0;
}
sub is_inf
my ($self,$x,$sign) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
$sign = '' if !defined $sign;
+ return 1 if $sign eq $x->{sign}; # match ("+inf" eq "+inf")
return 0 if $sign !~ /^([+-]|)$/;
if ($sign eq '')
}
$sign = quotemeta($sign.'inf');
return 1 if ($x->{sign} =~ /^$sign$/);
- return 0;
+ 0;
}
sub is_one
{
# multiply two numbers -- stolen from Knuth Vol 2 pg 233
# (BINT or num_str, BINT or num_str) return BINT
- my ($self,$x,$y,@r) = objectify(2,@_);
+
+ # 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('bmul');
- $r[3] = $y; # no push here
-
return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
# inf handling
return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
return $x->binf('-');
}
+
+ return $upgrade->bmul($x,$y,@r)
+ if defined $upgrade && $y->isa($upgrade);
+
+ $r[3] = $y; # no push here
$x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; # +1 * +1 or -1 * -1 => +
$x->{value} = $CALC->_mul($x->{value},$y->{value}); # do actual math
$x->{sign} = '+' if $CALC->_is_zero($x->{value}); # no -0
- $x->round(@r);
+
+ $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ $x;
}
sub _div_inf
# x / +-inf => 0, remainder x (works even if x == 0)
if ($y->{sign} =~ /^[+-]inf$/)
{
- my $t = $x->copy(); # binf clobbers up $x
+ my $t = $x->copy(); # bzero clobbers up $x
return wantarray ? ($x->bzero(),$t) : $x->bzero()
}
{
# (dividend: BINT or num_str, divisor: BINT or num_str) return
# (BINT,BINT) (quo,rem) or BINT (only rem)
- my ($self,$x,$y,@r) = objectify(2,@_);
+
+ # 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('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
my $cmp = $CALC->_acmp($x->{value},$y->{value});
if (($cmp < 0) and (($x->{sign} eq $y->{sign}) or !wantarray))
{
- return $upgrade->bdiv($x,$y,@r) if defined $upgrade;
+ 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 unless wantarray;
return ($x->round(@r),$self->bzero(@r));
}
+ return $upgrade->bdiv($upgrade->new($x),$upgrade->new($y),@r)
+ if defined $upgrade;
# calc new sign and in case $y == +/- 1, return $x
my $xsign = $x->{sign}; # keep
return wantarray ? ($x->round(@r),$self->bzero(@r)) : $x->round(@r);
}
- my $rem;
if (wantarray)
{
my $rem = $self->bzero();
($x->{value},$rem->{value}) = $CALC->_div($x->{value},$y->{value});
$x->{sign} = '+' if $CALC->_is_zero($x->{value});
+ $rem->{_a} = $x->{_a};
+ $rem->{_p} = $x->{_p};
$x->round(@r);
if (! $CALC->_is_zero($rem->{value}))
{
{
$rem->{sign} = '+'; # dont leave -0
}
- $rem->round(@r);
- return ($x,$rem);
+ return ($x,$rem->round(@r));
}
$x->{value} = $CALC->_div($x->{value},$y->{value});
$x->{sign} = '+' if $CALC->_is_zero($x->{value});
- $x->round(@r);
+
+ $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
$x;
}
+###############################################################################
+# modulus functions
+
sub bmod
{
# modulus (or remainder)
# (BINT or num_str, BINT or num_str) return BINT
- my ($self,$x,$y,@r) = objectify(2,@_);
-
+
+ # 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('bmod');
$r[3] = $y; # no push!
if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero())
{
my ($d,$r) = $self->_div_inf($x,$y);
- return $r->round(@r);
+ $x->{sign} = $r->{sign};
+ $x->{value} = $r->{value};
+ return $x->round(@r);
}
if ($CALC->can('_mod'))
{
my $xsign = $x->{sign};
$x->{sign} = $y->{sign};
- $x = $y-$x if $xsign ne $y->{sign}; # one of them '-'
+ if ($xsign ne $y->{sign})
+ {
+ my $t = $CALC->_copy($x->{value}); # copy $x
+ $x->{value} = $CALC->_copy($y->{value}); # copy $y to $x
+ $x->{value} = $CALC->_sub($y->{value},$t,1); # $y-$x
+ }
}
else
{
$x->{sign} = '+'; # dont leave -0
}
- return $x->round(@r);
+ $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ return $x;
}
my ($t,$rem) = $self->bdiv($x->copy(),$y,@r); # slow way (also rounds)
# modify in place
$x;
}
+sub bmodinv
+ {
+ # Modular inverse. given a number which is (hopefully) relatively
+ # prime to the modulus, calculate its inverse using Euclid's
+ # alogrithm. If the number is not relatively prime to the modulus
+ # (i.e. their gcd is not one) then NaN is returned.
+
+ # 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('bmodinv');
+
+ return $x->bnan()
+ if ($y->{sign} ne '+' # -, NaN, +inf, -inf
+ || $x->is_zero() # or num == 0
+ || $x->{sign} !~ /^[+-]$/ # or num NaN, inf, -inf
+ );
+
+ # put least residue into $x if $x was negative, and thus make it positive
+ $x->bmod($y) if $x->{sign} eq '-';
+
+ if ($CALC->can('_modinv'))
+ {
+ my $sign;
+ ($x->{value},$sign) = $CALC->_modinv($x->{value},$y->{value});
+ $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;
+ }
+ my ($u, $u1) = ($self->bzero(), $self->bone());
+ my ($a, $b) = ($y->copy(), $x->copy());
+
+ # first step need always be done since $num (and thus $b) is never 0
+ # Note that the loop is aligned so that the check occurs between #2 and #1
+ # thus saving us one step #2 at the loop end. Typical loop count is 1. Even
+ # a case with 28 loops still gains about 3% with this layout.
+ my $q;
+ ($a, $q, $b) = ($b, $a->bdiv($b)); # step #1
+ # Euclid's Algorithm (calculate GCD of ($a,$b) in $a and also calculate
+ # two values in $u and $u1, we use only $u1 afterwards)
+ my $sign = 1; # flip-flop
+ while (!$b->is_zero()) # found GCD if $b == 0
+ {
+ # the original algorithm had:
+ # ($u, $u1) = ($u1, $u->bsub($u1->copy()->bmul($q))); # step #2
+ # The following creates exact the same sequence of numbers in $u1,
+ # except for the sign ($u1 is now always positive). Since formerly
+ # the sign of $u1 was alternating between '-' and '+', the $sign
+ # flip-flop will take care of that, so that at the end of the loop
+ # we have the real sign of $u1. Keeping numbers positive gains us
+ # speed since badd() is faster than bsub() and makes it possible
+ # to have the algorithmn in Calc for even more speed.
+
+ ($u, $u1) = ($u1, $u->badd($u1->copy()->bmul($q))); # step #2
+ $sign = - $sign; # flip sign
+
+ ($a, $q, $b) = ($b, $a->bdiv($b)); # step #1 again
+ }
+
+ # If the gcd is not 1, then return NaN! It would be pointless to
+ # have called bgcd to check this first, because we would then be
+ # performing the same Euclidean Algorithm *twice*.
+ return $x->bnan() unless $a->is_one();
+
+ $u1->bneg() if $sign != 1; # need to flip?
+
+ $u1->bmod($y); # calc result
+ $x->{value} = $u1->{value}; # and copy over to $x
+ $x->{sign} = $u1->{sign}; # to modify in place
+ $x;
+ }
+
+sub bmodpow
+ {
+ # takes a very large number to a very large exponent in a given very
+ # large modulus, quickly, thanks to binary exponentation. supports
+ # negative exponents.
+ my ($self,$num,$exp,$mod,@r) = objectify(3,@_);
+
+ return $num if $num->modify('bmodpow');
+
+ # check modulus for valid values
+ return $num->bnan() if ($mod->{sign} ne '+' # NaN, - , -inf, +inf
+ || $mod->is_zero());
+
+ # check exponent for valid values
+ if ($exp->{sign} =~ /\w/)
+ {
+ # i.e., if it's NaN, +inf, or -inf...
+ return $num->bnan();
+ }
+
+ $num->bmodinv ($mod) if ($exp->{sign} eq '-');
+
+ # check num for valid values (also NaN if there was no inverse but $exp < 0)
+ return $num->bnan() if $num->{sign} !~ /^[+-]$/;
+
+ if ($CALC->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;
+ }
+
+ # in the trivial case,
+ return $num->bzero(@r) if $mod->is_one();
+ return $num->bone('+',@r) if $num->is_zero() or $num->is_one();
+
+ # $num->bmod($mod); # if $x is large, make it smaller first
+ my $acc = $num->copy(); # but this is not really faster...
+
+ $num->bone(); # keep ref to $num
+
+ my $expbin = $exp->as_bin(); $expbin =~ s/^[-]?0b//; # ignore sign and prefix
+ my $len = length($expbin);
+ while (--$len >= 0)
+ {
+ if( substr($expbin,$len,1) eq '1')
+ {
+ $num->bmul($acc)->bmod($mod);
+ }
+ $acc->bmul($acc)->bmod($mod);
+ }
+
+ $num;
+ }
+
+###############################################################################
+
sub bfac
{
# (BINT or num_str, BINT or num_str) return BINT
# compute factorial numbers
# modifies first argument
- my ($self,$x,@r) = objectify(1,@_);
+ my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
return $x if $x->modify('bfac');
return $x->bnan() if $x->{sign} ne '+'; # inf, NnN, <0 etc => NaN
- return $x->bone(@r) if $x->is_zero() || $x->is_one(); # 0 or 1 => 1
+ return $x->bone('+',@r) if $x->is_zero() || $x->is_one(); # 0 or 1 => 1
if ($CALC->can('_fac'))
{
my $n = $x->copy();
$x->bone();
+ # seems we need not to temp. clear A/P of $x since the result is the same
my $f = $self->new(2);
while ($f->bacmp($n) < 0)
{
$x->bmul($f); $f->binc();
}
- $x->bmul($f); # last step
- $x->round(@r); # round
+ $x->bmul($f,@r); # last step and also round
}
sub bpow
# (BINT or num_str, BINT or num_str) return BINT
# compute power of two numbers -- stolen from Knuth Vol 2 pg 233
# modifies first argument
- my ($self,$x,$y,@r) = objectify(2,@_);
+
+ # 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('bpow');
-
+
+ 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;
- return $x->bone(@r) if $y->is_zero();
+ return $x->bone('+',@r) if $y->is_zero();
return $x->round(@r) if $x->is_one() || $y->is_one();
if ($x->{sign} eq '-' && $CALC->_is_one($x->{value}))
{
if ($CALC->can('_pow'))
{
$x->{value} = $CALC->_pow($x->{value},$y->{value});
- return $x->round(@r);
+ $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ return $x;
}
# based on the assumption that shifting in base 10 is fast, and that mul
# stripping them out of the multiplication, and add $count * $y zeros
# afterwards like this:
# 300 ** 3 == 300*300*300 == 3*3*3 . '0' x 2 * 3 == 27 . '0' x 6
-# creates deep recursion?
+# creates deep recursion since brsft/blsft use bpow sometimes.
# my $zeros = $x->_trailing_zeros();
# if ($zeros > 0)
# {
# $x->bpow($y); # recursion (will not branch into here again)
# $zeros = $y * $zeros; # real number of zeros to add
# $x->blsft($zeros,10);
-# return $x->round($a,$p,$r);
+# return $x->round(@r);
# }
my $pow2 = $self->__one();
- my $y1 = $class->new($y);
- my $two = $self->new(2);
- while (!$y1->is_one())
+ my $y_bin = $y->as_bin(); $y_bin =~ s/^0b//;
+ my $len = length($y_bin);
+ while (--$len > 0)
{
- $pow2->bmul($x) if $y1->is_odd();
- $y1->bdiv($two);
+ $pow2->bmul($x) if substr($y_bin,$len,1) eq '1'; # is odd?
$x->bmul($x);
}
- $x->bmul($pow2) unless $pow2->is_one();
- return $x->round(@r);
+ $x->bmul($pow2);
+ $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+ $x;
}
sub blsft
{
# (BINT or num_str, BINT or num_str) return BINT
# compute x << y, base n, y >= 0
- my ($self,$x,$y,$n,$a,$p,$r) = objectify(2,@_);
-
+
+ # set up parameters
+ my ($self,$x,$y,$n,@r) = (ref($_[0]),@_);
+ # objectify is costly, so avoid it
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+ {
+ ($self,$x,$y,$n,@r) = objectify(2,@_);
+ }
+
return $x if $x->modify('blsft');
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
- return $x->round($a,$p,$r) if $y->is_zero();
+ return $x->round(@r) if $y->is_zero();
$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 $CALC->can('_lsft');
if (defined $t)
{
- $x->{value} = $t; return $x->round($a,$p,$r);
+ $x->{value} = $t; return $x->round(@r);
}
# fallback
- return $x->bmul( $self->bpow($n, $y, $a, $p, $r), $a, $p, $r );
+ return $x->bmul( $self->bpow($n, $y, @r), @r );
}
sub brsft
{
# (BINT or num_str, BINT or num_str) return BINT
# compute x >> y, base n, y >= 0
- my ($self,$x,$y,$n,$a,$p,$r) = objectify(2,@_);
+
+ # set up parameters
+ my ($self,$x,$y,$n,@r) = (ref($_[0]),@_);
+ # objectify is costly, so avoid it
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+ {
+ ($self,$x,$y,$n,@r) = objectify(2,@_);
+ }
return $x if $x->modify('brsft');
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
- return $x->round($a,$p,$r) if $y->is_zero();
- return $x->bzero($a,$p,$r) if $x->is_zero(); # 0 => 0
+ return $x->round(@r) if $y->is_zero();
+ return $x->bzero(@r) if $x->is_zero(); # 0 => 0
$n = 2 if !defined $n; return $x->bnan() if $n <= 0 || $y->{sign} eq '-';
# this only works for negative numbers when shifting in base 2
if (($x->{sign} eq '-') && ($n == 2))
{
- return $x->round($a,$p,$r) if $x->is_one('-'); # -1 => -1
+ return $x->round(@r) if $x->is_one('-'); # -1 => -1
if (!$y->is_one())
{
# although this is O(N*N) in calc (as_bin!) it is O(N) in Pari et al
$bin =~ s/^-0b//; # strip '-0b' prefix
$bin =~ tr/10/01/; # flip bits
# now shift
- if (length($bin) <= $y)
+ if (CORE::length($bin) <= $y)
{
$bin = '0'; # shifting to far right creates -1
# 0, because later increment makes
my $res = $self->new('0b'.$bin); # add prefix and convert back
$res->binc(); # remember to increment
$x->{value} = $res->{value}; # take over value
- return $x->round($a,$p,$r); # we are done now, magic, isn't?
+ return $x->round(@r); # we are done now, magic, isn't?
}
$x->bdec(); # n == 2, but $y == 1: this fixes it
}
if (defined $t)
{
$x->{value} = $t;
- return $x->round($a,$p,$r);
+ return $x->round(@r);
}
# fallback
- $x->bdiv($self->bpow($n,$y, $a,$p,$r), $a,$p,$r);
+ $x->bdiv($self->bpow($n,$y, @r), @r);
$x;
}
{
#(BINT or num_str, BINT or num_str) return BINT
# compute x & y
- my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
+
+ # 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('band');
+ $r[3] = $y; # no push!
local $Math::BigInt::upgrade = undef;
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
- return $x->bzero() if $y->is_zero() || $x->is_zero();
+ return $x->bzero(@r) if $y->is_zero() || $x->is_zero();
my $sign = 0; # sign of result
$sign = 1 if ($x->{sign} eq '-') && ($y->{sign} eq '-');
if ($CALC->can('_and') && $sx == 1 && $sy == 1)
{
$x->{value} = $CALC->_and($x->{value},$y->{value});
- return $x->round($a,$p,$r);
+ return $x->round(@r);
}
my $m = $self->bone(); my ($xr,$yr);
$m->bmul($x10000);
}
$x->bneg() if $sign;
- return $x->round($a,$p,$r);
+ $x->round(@r);
}
sub bior
{
#(BINT or num_str, BINT or num_str) return BINT
# compute x | y
- my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
+
+ # 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('bior');
+ $r[3] = $y; # no push!
local $Math::BigInt::upgrade = undef;
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
- return $x if $y->is_zero();
+ return $x->round(@r) if $y->is_zero();
my $sign = 0; # sign of result
$sign = 1 if ($x->{sign} eq '-') || ($y->{sign} eq '-');
if ($CALC->can('_or') && $sx == 1 && $sy == 1)
{
$x->{value} = $CALC->_or($x->{value},$y->{value});
- return $x->round($a,$p,$r);
+ return $x->round(@r);
}
my $m = $self->bone(); my ($xr,$yr);
$m->bmul($x10000);
}
$x->bneg() if $sign;
- return $x->round($a,$p,$r);
+ $x->round(@r);
}
sub bxor
{
#(BINT or num_str, BINT or num_str) return BINT
# compute x ^ y
- my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
+
+ # 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('bxor');
+ $r[3] = $y; # no push!
local $Math::BigInt::upgrade = undef;
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
- return $x if $y->is_zero();
+ return $x->round(@r) if $y->is_zero();
my $sign = 0; # sign of result
$sign = 1 if $x->{sign} ne $y->{sign};
if ($CALC->can('_xor') && $sx == 1 && $sy == 1)
{
$x->{value} = $CALC->_xor($x->{value},$y->{value});
- return $x->round($a,$p,$r);
+ return $x->round(@r);
}
my $m = $self->bone(); my ($xr,$yr);
$m->bmul($x10000);
}
$x->bneg() if $sign;
- return $x->round($a,$p,$r);
+ $x->round(@r);
}
sub length
sub digit
{
# return the nth decimal digit, negative values count backward, 0 is right
- my $x = shift;
- my $n = shift || 0;
+ my ($self,$x,$n) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
- return $CALC->_digit($x->{value},$n);
+ $CALC->_digit($x->{value},$n||0);
}
sub _trailing_zeros
# if not: since we do not know underlying internal representation:
my $es = "$x"; $es =~ /([0]*)$/;
return 0 if !defined $1; # no zeros
- return CORE::length("$1"); # as string, not as +0!
+ CORE::length("$1"); # as string, not as +0!
}
sub bsqrt
{
- my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+ 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($a,$p) if $x->is_zero(); # 0 => 0
- return $x->round($a,$p,$r) if $x->is_one(); # 1 => 1
+ return $x->bzero(@r) if $x->is_zero(); # 0 => 0
+ return $x->round(@r) if $x->is_one(); # 1 => 1
- return $upgrade->bsqrt($x,$a,$p,$r) if defined $upgrade;
+ return $upgrade->bsqrt($x,@r) if defined $upgrade;
if ($CALC->can('_sqrt'))
{
$x->{value} = $CALC->_sqrt($x->{value});
- return $x->round($a,$p,$r);
+ return $x->round(@r);
}
- return $x->bone($a,$p) if $x < 4; # 2,3 => 1
+ return $x->bone('+',@r) if $x < 4; # 2,3 => 1
my $y = $x->copy();
my $l = int($x->length()/2);
my $lastlast = $x+$two;
while ($last != $x && $lastlast != $x)
{
- $lastlast = $last; $last = $x;
- $x += $y / $x;
- $x /= $two;
+ $lastlast = $last; $last = $x->copy();
+ $x->badd($y / $x);
+ $x->bdiv($two);
}
- $x-- if $x * $x > $y; # overshot?
- $x->round($a,$p,$r);
+ $x->bdec() if $x * $x > $y; # overshot?
+ $x->round(@r);
}
sub exponent
my $e = $class->bzero();
return $e->binc() if $x->is_zero();
$e += $x->_trailing_zeros();
- return $e;
+ $e;
}
sub mantissa
if ($x->{sign} !~ /^[+-]$/)
{
- my $s = $x->{sign}; $s =~ s/^[+]//;
- return $self->new($s); # +inf => inf
+ return $self->new($x->{sign}); # keep + or - sign
}
my $m = $x->copy();
# that's inefficient
my $zeros = $m->_trailing_zeros();
- $m /= 10 ** $zeros if $zeros != 0;
- return $m;
+ $m->brsft($zeros,10) if $zeros != 0;
+ $m;
}
sub parts
# since we do not know underlying represention of $x, use decimal string
#my $r = substr ($$xs,-$follow);
my $r = substr ("$x",-$follow);
- return 1 if $r =~ /[^0]/; return 0;
+ return 1 if $r =~ /[^0]/;
+ 0;
}
sub fround
# we have fewer digits than we want to scale to
my $len = $x->length();
+ # convert $scale to a scalar in case it is an object (put's a limit on the
+ # number length, but this would already limited by memory constraints), makes
+ # it faster
+ $scale = $scale->numify() if ref ($scale);
+
# scale < 0, but > -len (not >=!)
if (($scale < 0 && $scale < -$len-1) || ($scale >= $len))
{
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;
$pl++; $pl ++ if $pad >= $len;
$digit_after = '0'; $digit_after = substr($$xs,$pl,1) if $pad > 0;
- # print "$pad $pl $$xs dr $digit_round da $digit_after\n";
-
# 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
my $round_up = 1; # default round up
);
my $put_back = 0; # not yet modified
- # old code, depend on internal representation
- # split mantissa at $pad and then pad with zeros
- #my $s5 = int($pad / 5);
- #my $i = 0;
- #while ($i < $s5)
- # {
- # $x->{value}->[$i++] = 0; # replace with 5 x 0
- # }
- #$x->{value}->[$s5] = '00000'.$x->{value}->[$s5]; # pad with 0
- #my $rem = $pad % 5; # so much left over
- #if ($rem > 0)
- # {
- # #print "remainder $rem\n";
- ## #print "elem $x->{value}->[$s5]\n";
- # substr($x->{value}->[$s5],-$rem,$rem) = '0' x $rem; # stamp w/ '0'
- # }
- #$x->{value}->[$s5] = int ($x->{value}->[$s5]); # str '05' => int '5'
- #print ${$CALC->_str($pad->{value})}," $len\n";
-
if (($pad > 0) && ($pad <= $len))
{
substr($$xs,-$pad,$pad) = '0' x $pad;
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
+ $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
+ # adding it, since that is faster (we already have the string)
my $c = 0; $pad ++; # for $pad == $len case
while ($pad <= $len)
{
}
$$xs = '1'.$$xs if $c == 0;
- # $x->badd( Math::BigInt->new($x->{sign}.'1'. '0' x $pad) );
}
- $x->{value} = $CALC->_new($xs) if $put_back == 1; # put back in
+ $x->{value} = $CALC->_new($xs) if $put_back == 1; # put back in if needed
$x->{_a} = $scale if $scale >= 0;
if ($scale < 0)
{
# return integer less or equal then number, since it is already integer,
# always returns $self
- my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+ my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
- # not needed: return $x if $x->modify('bfloor');
- return $x->round($a,$p,$r);
+ $x->round(@r);
}
sub bceil
{
# return integer greater or equal then number, since it is already integer,
# always returns $self
- my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+ my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
- # not needed: return $x if $x->modify('bceil');
- return $x->round($a,$p,$r);
+ $x->round(@r);
}
##############################################################################
my $self = shift;
my $x = $self->bone(); # $x->{value} = $CALC->_one();
$x->{sign} = shift || '+';
- return $x;
+ $x;
}
sub _swap
# currently it tries 'Math::BigInt' + 1, which will not work.
# some shortcut for the common cases
-
# $x->unary_op();
return (ref($_[1]),$_[1]) if (@_ == 2) && ($_[0]||0 == 1) && ref($_[1]);
- # $x->binary_op($y);
- #return (ref($_[1]),$_[1],$_[2]) if (@_ == 3) && ($_[0]||0 == 2)
- # && ref($_[1]) && ref($_[2]);
my $count = abs(shift || 0);
- my @a; # resulting array
+ my (@a,$k,$d); # resulting array, temp, and downgrade
if (ref $_[0])
{
# okay, got object as first
$a[0] = $class;
$a[0] = shift if $_[0] =~ /^[A-Z].*::/; # classname as first?
}
+
+ no strict 'refs';
+ # disable downgrading, because Math::BigFLoat->foo('1.0','2.0') needs floats
+ if (defined ${"$a[0]::downgrade"})
+ {
+ $d = ${"$a[0]::downgrade"};
+ ${"$a[0]::downgrade"} = undef;
+ }
+
+ my $up = ${"$a[0]::upgrade"};
# print "Now in objectify, my class is today $a[0]\n";
- my $k;
if ($count == 0)
{
while (@_)
{
$k = $a[0]->new($k);
}
- elsif (ref($k) ne $a[0])
+ elsif (!defined $up && ref($k) ne $a[0])
{
# foreign object, try to convert to integer
$k->can('as_number') ? $k = $k->as_number() : $k = $a[0]->new($k);
{
$k = $a[0]->new($k);
}
- elsif (ref($k) ne $a[0])
+ elsif (!defined $up && ref($k) ne $a[0])
{
# foreign object, try to convert to integer
$k->can('as_number') ? $k = $k->as_number() : $k = $a[0]->new($k);
push @a,@_; # return other params, too
}
die "$class objectify needs list context" unless wantarray;
+ ${"$a[0]::downgrade"} = $d;
@a;
}
my $self = shift;
$IMPORT++;
- my @a = @_; my $l = scalar @_; my $j = 0;
- for ( my $i = 0; $i < $l ; $i++,$j++ )
+ my @a; my $l = scalar @_;
+ for ( my $i = 0; $i < $l ; $i++ )
{
if ($_[$i] eq ':constant')
{
# this causes overlord er load to step in
overload::constant integer => sub { $self->new(shift) };
- splice @a, $j, 1; $j --;
+ overload::constant binary => sub { $self->new(shift) };
}
elsif ($_[$i] eq 'upgrade')
{
# this causes upgrading
$upgrade = $_[$i+1]; # or undef to disable
- my $s = 2; $s = 1 if @a-$j < 2; # avoid "can not modify non-existant..."
- splice @a, $j, $s; $j -= $s;
+ $i++;
}
elsif ($_[$i] =~ /^lib$/i)
{
# this causes a different low lib to take care...
$CALC = $_[$i+1] || '';
- my $s = 2; $s = 1 if @a-$j < 2; # avoid "can not modify non-existant..."
- splice @a, $j, $s; $j -= $s;
+ $i++;
+ }
+ else
+ {
+ push @a, $_[$i];
}
}
# any non :constant stuff is handled by our parent, Exporter
$CALC = ''; # signal error
foreach my $lib (@c)
{
+ next if ($lib || '') eq '';
$lib = 'Math::BigInt::'.$lib if $lib !~ /^Math::BigInt/i;
$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().
- (my $mod = $lib . '.pm') =~ s!::!/!g;
- # require does not automatically :: => /, so portability problems arise
- eval { require $mod; $lib->import( @c ); }
+ my @parts = split /::/, $lib; # Math::BigInt => Math BigInt
+ my $file = pop @parts; $file .= '.pm'; # BigInt => BigInt.pm
+ require File::Spec;
+ $file = File::Spec->catfile (@parts, $file);
+ eval { require "$file"; $lib->import( @c ); }
}
else
{
$mul *= $x65536 if $len >= 0; # skip last mul
}
}
- $x->{sign} = $sign if !$x->is_zero(); # no '-0'
- return $x;
+ $x->{sign} = $sign unless $CALC->_is_zero($x->{value}); # no '-0'
+ $x;
}
sub __from_bin
$$bs =~ s/([01])_([01])/$1$2/g;
return $x->bnan() if $$bs !~ /^[+-]?0b[01]+$/;
- my $mul = Math::BigInt->bzero(); $mul++;
- my $x256 = Math::BigInt->new(256);
-
my $sign = '+'; $sign = '-' if ($$bs =~ /^\-/);
$$bs =~ s/^[+-]//; # strip sign
if ($CALC->can('_from_bin'))
}
else
{
+ my $mul = Math::BigInt->bzero(); $mul++;
+ my $x256 = Math::BigInt->new(256);
my $len = CORE::length($$bs)-2;
$len = int($len/8); # 8-digit parts, w/o '0b'
my $val; my $i = -8;
$mul *= $x256 if $len >= 0; # skip last mul
}
}
- $x->{sign} = $sign if !$x->is_zero();
- return $x;
+ $x->{sign} = $sign unless $CALC->_is_zero($x->{value}); # no '-0'
+ $x;
}
sub _split
$$x =~ s/\s+$//g; # strip white space at end
# shortcut, if nothing to split, return early
- if ($$x =~ /^[+-]?\d+$/)
+ if ($$x =~ /^[+-]?\d+\z/)
{
$$x =~ s/^([+-])0*([0-9])/$2/; my $sign = $1 || '+';
return (\$sign, $x, \'', \'', \0);
# 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
- return if $$x =~ /[Ee].*[Ee]/; # more than one E => error
+ #return if $$x =~ /[Ee].*[Ee]/; # more than one E => error
- my ($m,$e) = 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 "";
+
# sign,value for exponent,mantint,mantfrac
my ($es,$ev,$mis,$miv,$mfv);
# valid exponent?
$es = $1; $ev = $2;
# valid mantissa?
return if $m eq '.' || $m eq '';
- my ($mi,$mf) = split /\./,$m;
+ my ($mi,$mf,$lastf) = split /\./,$m;
+ return if defined $lastf; # last defined => 1.2.3 or others
$mi = '0' if !defined $mi;
$mi .= '0' if $mi =~ /^[\-\+]?$/;
$mf = '0' if !defined $mf || $mf eq '';
}
else
{
- my $x1 = $x->copy()->babs(); my $xr;
- my $x10000 = Math::BigInt->new (0x10000);
+ my $x1 = $x->copy()->babs(); my ($xr,$x10000,$h);
+ if ($] >= 5.006)
+ {
+ $x10000 = Math::BigInt->new (0x10000); $h = 'h4';
+ }
+ else
+ {
+ $x10000 = Math::BigInt->new (0x1000); $h = 'h3';
+ }
while (!$x1->is_zero())
{
($x1, $xr) = bdiv($x1,$x10000);
- $es .= unpack('h4',pack('v',$xr->numify()));
+ $es .= unpack($h,pack('v',$xr->numify()));
}
$es = reverse $es;
$es =~ s/^[0]+//; # strip leading zeros
}
else
{
- my $x1 = $x->copy()->babs(); my $xr;
- my $x10000 = Math::BigInt->new (0x10000);
+ my $x1 = $x->copy()->babs(); my ($xr,$x10000,$b);
+ if ($] >= 5.006)
+ {
+ $x10000 = Math::BigInt->new (0x10000); $b = 'b16';
+ }
+ else
+ {
+ $x10000 = Math::BigInt->new (0x1000); $b = 'b12';
+ }
while (!$x1->is_zero())
{
($x1, $xr) = bdiv($x1,$x10000);
- $es .= unpack('b16',pack('v',$xr->numify()));
+ $es .= unpack($b,pack('v',$xr->numify()));
}
$es = reverse $es;
$es =~ s/^[0]+//; # strip leading zeros
$one = Math::BigInt->bone(); # create a +1
$one = Math::BigInt->bone('-'); # create a -1
- # Testing
- $x->is_zero(); # true if arg is +0
- $x->is_nan(); # true if arg is NaN
- $x->is_one(); # true if arg is +1
- $x->is_one('-'); # true if arg is -1
- $x->is_odd(); # true if odd, false for even
- $x->is_even(); # true if even, false for odd
- $x->is_positive(); # true if >= 0
- $x->is_negative(); # true if < 0
- $x->is_inf(sign); # true if +inf, or -inf (sign is default '+')
- $x->is_int(); # true if $x is an integer (not a float)
-
- $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
- $x->digit($n); # return the nth digit, counting from right
- $x->digit(-$n); # return the nth digit, counting from left
+ # Testing (don't modify their arguments)
+ # (return true if the condition is met, otherwise false)
+
+ $x->is_zero(); # if $x is +0
+ $x->is_nan(); # if $x is NaN
+ $x->is_one(); # if $x is +1
+ $x->is_one('-'); # if $x is -1
+ $x->is_odd(); # if $x is odd
+ $x->is_even(); # if $x is even
+ $x->is_positive(); # if $x >= 0
+ $x->is_negative(); # if $x < 0
+ $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
+ $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
+ $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:
- # set
- $x->bzero(); # set $x to 0
- $x->bnan(); # set $x to NaN
- $x->bone(); # set $x to +1
- $x->bone('-'); # set $x to -1
- $x->binf(); # set $x to inf
- $x->binf('-'); # set $x to -inf
-
- $x->bneg(); # negation
- $x->babs(); # absolute value
- $x->bnorm(); # normalize (no-op)
- $x->bnot(); # two's complement (bit wise not)
- $x->binc(); # increment x by 1
- $x->bdec(); # decrement x by 1
+ $x->bzero(); # set $x to 0
+ $x->bnan(); # set $x to NaN
+ $x->bone(); # set $x to +1
+ $x->bone('-'); # set $x to -1
+ $x->binf(); # set $x to inf
+ $x->binf('-'); # set $x to -inf
+
+ $x->bneg(); # negation
+ $x->babs(); # absolute value
+ $x->bnorm(); # normalize (no-op in BigInt)
+ $x->bnot(); # two's complement (bit wise not)
+ $x->binc(); # increment $x by 1
+ $x->bdec(); # decrement $x by 1
- $x->badd($y); # addition (add $y to $x)
- $x->bsub($y); # subtraction (subtract $y from $x)
- $x->bmul($y); # multiplication (multiply $x by $y)
- $x->bdiv($y); # divide, set $x to quotient
- # return (quo,rem) or quo if scalar
-
- $x->bmod($y); # modulus (x % y)
- $x->bpow($y); # power of arguments (x ** y)
- $x->blsft($y); # left shift
- $x->brsft($y); # right shift
- $x->blsft($y,$n); # left shift, by base $n (like 10)
- $x->brsft($y,$n); # right shift, by base $n (like 10)
+ $x->badd($y); # addition (add $y to $x)
+ $x->bsub($y); # subtraction (subtract $y from $x)
+ $x->bmul($y); # multiplication (multiply $x by $y)
+ $x->bdiv($y); # divide, set $x to quotient
+ # return (quo,rem) or quo if scalar
+
+ $x->bmod($y); # modulus (x % y)
+ $x->bmodpow($exp,$mod); # modular exponentation (($num**$exp) % $mod))
+ $x->bmodinv($mod); # the inverse of $x in the given modulus $mod
+
+ $x->bpow($y); # power of arguments (x ** y)
+ $x->blsft($y); # left shift
+ $x->brsft($y); # right shift
+ $x->blsft($y,$n); # left shift, by base $n (like 10)
+ $x->brsft($y,$n); # right shift, by base $n (like 10)
- $x->band($y); # bitwise and
- $x->bior($y); # bitwise inclusive or
- $x->bxor($y); # bitwise exclusive or
- $x->bnot(); # bitwise not (two's complement)
+ $x->band($y); # bitwise and
+ $x->bior($y); # bitwise inclusive or
+ $x->bxor($y); # bitwise exclusive or
+ $x->bnot(); # bitwise not (two's complement)
- $x->bsqrt(); # calculate square-root
- $x->bfac(); # factorial of $x (1*2*3*4*..$x)
+ $x->bsqrt(); # calculate square-root
+ $x->bfac(); # factorial of $x (1*2*3*4*..$x)
- $x->round($A,$P,$round_mode); # round to accuracy or precision using mode $r
- $x->bround($N); # accuracy: preserve $N digits
- $x->bfround($N); # round to $Nth digit, no-op for BigInts
+ $x->round($A,$P,$mode); # round to accuracy or precision using mode $r
+ $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, but do in BigFloat:
- $x->bfloor(); # return integer less or equal than $x
- $x->bceil(); # return integer greater or equal than $x
+ # The following do not modify their arguments in BigInt,
+ # but do so in BigFloat:
+
+ $x->bfloor(); # return integer less or equal than $x
+ $x->bceil(); # return integer greater or equal than $x
# The following do not modify their arguments:
- bgcd(@values); # greatest common divisor (no OO style)
- blcm(@values); # lowest common multiplicator (no OO style)
+ bgcd(@values); # greatest common divisor (no OO style)
+ blcm(@values); # lowest common multiplicator (no OO style)
- $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
-
- $x->exponent(); # return exponent as BigInt
- $x->mantissa(); # return (signed) mantissa as BigInt
- $x->parts(); # return (mantissa,exponent) as BigInt
- $x->copy(); # make a true copy of $x (unlike $y = $x;)
- $x->as_number(); # return as BigInt (in BigInt: same as copy())
+ $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
+
+ $x->exponent(); # return exponent as BigInt
+ $x->mantissa(); # return (signed) mantissa as BigInt
+ $x->parts(); # return (mantissa,exponent) as BigInt
+ $x->copy(); # make a true copy of $x (unlike $y = $x;)
+ $x->as_number(); # return as BigInt (in BigInt: same as copy())
+
+ # conversation to string (do not modify their argument)
+ $x->bstr(); # normalized string
+ $x->bsstr(); # normalized string in scientific notation
+ $x->as_hex(); # as signed hexadecimal string with prefixed 0x
+ $x->as_bin(); # as signed binary string with prefixed 0b
- # conversation to string
- $x->bstr(); # normalized string
- $x->bsstr(); # normalized string in scientific notation
- $x->as_hex(); # as signed hexadecimal string with prefixed 0x
- $x->as_bin(); # as signed binary string with prefixed 0b
+
+ # precision and accuracy (see section about rounding for more)
+ $x->precision(); # return P of $x (or global, if P of $x undef)
+ $x->precision($n); # set P of $x to $n
+ $x->accuracy(); # return A of $x (or global, if A of $x undef)
+ $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
=head1 DESCRIPTION
=head1 METHODS
-Each of the methods below accepts three additional parameters. These arguments
-$A, $P and $R are accuracy, precision and round_mode. Please see more in the
-section about ACCURACY and ROUNDIND.
+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
+L<ACCURACY and PRECISION> for more information.
+
+=head2 config
+
+ use Data::Dumper;
+
+ print Dumper ( Math::BigInt->config() );
+ print Math::BigInt->config()->{lib},"\n";
+
+Returns a hash containing the configuration, e.g. the version number, lib
+loaded etc. The following hash keys are currently filled in with the
+appropriate information.
+
+ key Description
+ Example
+ ============================================================
+ lib Name of the Math library
+ Math::BigInt::Calc
+ lib_version Version of 'lib'
+ 0.30
+ class The class of config you just called
+ Math::BigInt
+ upgrade To which class numbers are upgraded
+ Math::BigFloat
+ downgrade To which class numbers are downgraded
+ undef
+ precision Global precision
+ undef
+ accuracy Global accuracy
+ undef
+ round_mode Global round mode
+ even
+ version version number of the class you used
+ 1.61
+ div_scale Fallback acccuracy for div
+ 40
+
+It is currently not supported to set the configuration parameters by passing
+a hash ref to C<config()>.
+
+=head2 accuracy
+
+ $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
+
+Set or get the global or local accuracy, aka how many significant digits the
+results have.
+
+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:
+
+ $x->accuracy(undef);
+ Math::BigInt->accuracy(undef);
+
+Returns the current accuracy. For C<$x->accuracy()> it will return either the
+local accuracy, or if not defined, the global. This means the return value
+represents the accuracy that will be in effect for $x:
+
+ $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
+ print "$x $y\n"; # '123500 1234567'
+ print $x->accuracy(),"\n"; # will be 4
+ print $y->accuracy(),"\n"; # also 4, since global is 4
+ print Math::BigInt->accuracy(5),"\n"; # set to 5, print 5
+ print $x->accuracy(),"\n"; # still 4
+ print $y->accuracy(),"\n"; # 5, since global is 5
+
+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
+Math::BigInt and make the globals of the subclass aliases to the ones from
+Math::BigInt.
+
+=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
+
+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.
+
+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:
+
+ $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:
+
+ $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
+
+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
+Math::BigInt and make the globals of the subclass aliases to the ones from
+Math::BigInt.
=head2 brsft
$x->bone(); # +1
$x->bone('-'); # -1
-=head2 is_one()/is_zero()/is_nan()/is_positive()/is_negative()/is_inf()/is_odd()/is_even()/is_int()
+=head2 is_one()/is_zero()/is_nan()/is_inf()
+
$x->is_zero(); # true if arg is +0
$x->is_nan(); # true if arg is NaN
$x->is_one(); # true if arg is +1
$x->is_one('-'); # true if arg is -1
- $x->is_odd(); # true if odd, false for even
- $x->is_even(); # true if even, false for odd
- $x->is_positive(); # true if >= 0
- $x->is_negative(); # true if < 0
$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
+true or false depending on the input. These are faster than doing something
+like:
+
+ if ($x == 0)
+
+=head2 is_positive()/is_negative()
+
+ $x->is_positive(); # true if >= 0
+ $x->is_negative(); # 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.
+
+These methods are only testing the sign, and not the value.
+
+=head2 is_odd()/is_even()/is_int()
+
+ $x->is_odd(); # true if odd, false for even
+ $x->is_even(); # true if even, false for odd
$x->is_int(); # true if $x is an integer
-These methods all test the BigInt for one condition and return true or false
-depending on the input.
+The return true when the argument satisfies the condition. C<NaN>, C<+inf>,
+C<-inf> are not integers and are neither odd nor even.
=head2 bcmp
- $x->bcmp($y); # compare numbers (undef,<0,=0,>0)
+ $x->bcmp($y);
+
+Compares $x with $y and takes the sign into account.
+Returns -1, 0, 1 or undef.
=head2 bacmp
- $x->bacmp($y); # compare absolutely (undef,<0,=0,>0)
+ $x->bacmp($y);
+
+Compares $x with $y while ignoring their. Returns -1, 0, 1 or undef.
=head2 sign
- $x->sign(); # return the sign, either +,- or NaN
+ $x->sign();
+
+Return the sign, of $x, meaning either C<+>, C<->, C<-inf>, C<+inf> or NaN.
=head2 bcmp
=head2 bnorm
- $x->bnorm(); # normalize (no-op)
+ $x->bnorm(); # normalize (no-op)
=head2 bnot
- $x->bnot(); # two's complement (bit wise not)
+ $x->bnot(); # two's complement (bit wise not)
=head2 binc
- $x->binc(); # increment x by 1
+ $x->binc(); # increment x by 1
=head2 bdec
- $x->bdec(); # decrement x by 1
+ $x->bdec(); # decrement x by 1
=head2 badd
- $x->badd($y); # addition (add $y to $x)
+ $x->badd($y); # addition (add $y to $x)
=head2 bsub
- $x->bsub($y); # subtraction (subtract $y from $x)
+ $x->bsub($y); # subtraction (subtract $y from $x)
=head2 bmul
- $x->bmul($y); # multiplication (multiply $x by $y)
+ $x->bmul($y); # multiplication (multiply $x by $y)
=head2 bdiv
- $x->bdiv($y); # divide, set $x to quotient
- # return (quo,rem) or quo if scalar
+ $x->bdiv($y); # divide, set $x to quotient
+ # return (quo,rem) or quo if scalar
=head2 bmod
- $x->bmod($y); # modulus (x % y)
+ $x->bmod($y); # modulus (x % y)
+
+=head2 bmodinv
+
+ num->bmodinv($mod); # modular inverse
+
+Returns the inverse of C<$num> in the given modulus C<$mod>. 'C<NaN>' is
+returned unless C<$num> is relatively prime to C<$mod>, i.e. unless
+C<bgcd($num, $mod)==1>.
+
+=head2 bmodpow
+
+ $num->bmodpow($exp,$mod); # modular exponentation
+ # ($num**$exp % $mod)
+
+Returns the value of C<$num> taken to the power C<$exp> in the modulus
+C<$mod> using binary exponentation. C<bmodpow> is far superior to
+writing
+
+ $num ** $exp % $mod
+
+because C<bmodpow> is much faster--it reduces internal variables into
+the modulus whenever possible, so it operates on smaller numbers.
+
+C<bmodpow> also supports negative exponents.
+
+ bmodpow($num, -1, $mod)
+
+is exactly equivalent to
+
+ bmodinv($num, $mod)
=head2 bpow
- $x->bpow($y); # power of arguments (x ** y)
+ $x->bpow($y); # power of arguments (x ** y)
=head2 blsft
- $x->blsft($y); # left shift
- $x->blsft($y,$n); # left shift, by base $n (like 10)
+ $x->blsft($y); # left shift
+ $x->blsft($y,$n); # left shift, in base $n (like 10)
=head2 brsft
- $x->brsft($y); # right shift
- $x->brsft($y,$n); # right shift, by base $n (like 10)
+ $x->brsft($y); # right shift
+ $x->brsft($y,$n); # right shift, in base $n (like 10)
=head2 band
- $x->band($y); # bitwise and
+ $x->band($y); # bitwise and
=head2 bior
- $x->bior($y); # bitwise inclusive or
+ $x->bior($y); # bitwise inclusive or
=head2 bxor
- $x->bxor($y); # bitwise exclusive or
+ $x->bxor($y); # bitwise exclusive or
=head2 bnot
- $x->bnot(); # bitwise not (two's complement)
+ $x->bnot(); # bitwise not (two's complement)
=head2 bsqrt
- $x->bsqrt(); # calculate square-root
+ $x->bsqrt(); # calculate square-root
=head2 bfac
- $x->bfac(); # factorial of $x (1*2*3*4*..$x)
+ $x->bfac(); # factorial of $x (1*2*3*4*..$x)
=head2 round
- $x->round($A,$P,$round_mode); # round to accuracy or precision using mode $r
+ $x->round($A,$P,$round_mode);
+
+Round $x to accuracy C<$A> or precision C<$P> using the round mode
+C<$round_mode>.
=head2 bround
- $x->bround($N); # accuracy: preserve $N digits
+ $x->bround($N); # accuracy: preserve $N digits
=head2 bfround
- $x->bfround($N); # round to $Nth digit, no-op for BigInts
+ $x->bfround($N); # round to $Nth digit, no-op for BigInts
=head2 bfloor
=head2 bgcd
- bgcd(@values); # greatest common divisor (no OO style)
+ bgcd(@values); # greatest common divisor (no OO style)
=head2 blcm
- blcm(@values); # lowest common multiplicator (no OO style)
+ blcm(@values); # lowest common multiplicator (no OO style)
head2 length
=head2 parts
- $x->parts(); # return (mantissa,exponent) as BigInt
+ $x->parts(); # return (mantissa,exponent) as BigInt
=head2 copy
- $x->copy(); # make a true copy of $x (unlike $y = $x;)
+ $x->copy(); # make a true copy of $x (unlike $y = $x;)
=head2 as_number
- $x->as_number(); # return as BigInt (in BigInt: same as copy())
+ $x->as_number(); # return as BigInt (in BigInt: same as copy())
=head2 bsrt
- $x->bstr(); # normalized string
+ $x->bstr(); # return normalized string
=head2 bsstr
- $x->bsstr(); # normalized string in scientific notation
+ $x->bsstr(); # normalized string in scientific notation
=head2 as_hex
- $x->as_hex(); # as signed hexadecimal string with prefixed 0x
+ $x->as_hex(); # as signed hexadecimal string with prefixed 0x
=head2 as_bin
- $x->as_bin(); # as signed binary string with prefixed 0b
+ $x->as_bin(); # as signed binary string with prefixed 0b
=head1 ACCURACY and PRECISION
=head1 Autocreating constants
-After C<use Math::BigInt ':constant'> all the B<integer> decimal constants
-in the given scope are converted to C<Math::BigInt>. This conversion
-happens at compile time.
+After C<use Math::BigInt ':constant'> all the B<integer> decimal, hexadecimal
+and binary constants in the given scope are converted to C<Math::BigInt>.
+This conversion happens at compile time.
In particular,
perl -MMath::BigInt=:constant -e 'print 2**100,"\n"'
-prints the integer value of C<2**100>. Note that without conversion of
+prints the integer value of C<2**100>. Note that without conversion of
constants the expression 2**100 will be calculated as perl scalar.
Please note that strings and floating point constants are not affected,
constant at compile time and then hand the result to BigInt, which results in
an truncated result or a NaN.
+This also applies to integers that look like floating point constants:
+
+ use Math::BigInt ':constant';
+
+ print ref(123e2),"\n";
+ print ref(123.2e2),"\n";
+
+will print nothing but newlines. Use either L<bignum> or L<Math::BigFloat>
+to get this to work.
+
=head1 PERFORMANCE
Using the form $x += $y; etc over $x = $x + $y is faster, since a copy of $x