# return result as BFLOAT
# set up parameters
- my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);
+ my ($self,$x,$y,@r) = (ref($_[0]),@_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
- ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
+ ($self,$x,$y,@r) = objectify(2,@_);
}
return $x if $x->modify('badd');
return $x;
}
- return $upgrade->badd($x,$y,$a,$p,$r) if defined $upgrade &&
+ return $upgrade->badd($x,$y,@r) if defined $upgrade &&
((!$x->isa($self)) || (!$y->isa($self)));
+ $r[3] = $y; # no push!
+
# speed: no add for 0+y or x+0
- return $x->bround($a,$p,$r) if $y->is_zero(); # x+0
+ return $x->bround(@r) if $y->is_zero(); # x+0
if ($x->is_zero()) # 0+y
{
# make copy, clobbering up x (modify in place!)
$x->{_es} = $y->{_es};
$x->{_m} = $MBI->_copy($y->{_m});
$x->{sign} = $y->{sign} || $nan;
- return $x->round($a,$p,$r,$y);
+ return $x->round(@r);
}
# take lower of the two e's and adapt m1 to it to match m2
}
# delete trailing zeros, then round
- $x->bnorm()->round($a,$p,$r,$y);
+ $x->bnorm()->round(@r);
}
# sub bsub is inherited from Math::BigInt!
# return true if arg (BFLOAT or num_str) is an integer
my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
- return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't
- $x->{_es} eq '+'; # 1e-1 => no integer
- 0;
+ (($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't
+ ($x->{_es} eq '+')) ? 1 : 0; # 1e-1 => no integer
}
sub is_zero
# return true if arg (BFLOAT or num_str) is zero
my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
- return 1 if $x->{sign} eq '+' && $MBI->_is_zero($x->{_m});
- 0;
+ ($x->{sign} eq '+' && $MBI->_is_zero($x->{_m})) ? 1 : 0;
}
sub is_one
my ($self,$x,$sign) = ref($_[0]) ? (undef,@_) : objectify(1,@_);
$sign = '+' if !defined $sign || $sign ne '-';
- return 1
- if ($x->{sign} eq $sign &&
- $MBI->_is_zero($x->{_e}) && $MBI->_is_one($x->{_m}));
- 0;
+
+ ($x->{sign} eq $sign &&
+ $MBI->_is_zero($x->{_e}) &&
+ $MBI->_is_one($x->{_m}) ) ? 1 : 0;
}
sub is_odd
# return true if arg (BFLOAT or num_str) is odd or false if even
my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
- return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
- ($MBI->_is_zero($x->{_e}) && $MBI->_is_odd($x->{_m}));
- 0;
+ (($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
+ ($MBI->_is_zero($x->{_e})) &&
+ ($MBI->_is_odd($x->{_m}))) ? 1 : 0;
}
sub is_even
# return true if arg (BINT or num_str) is even or false if odd
my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
- return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't
- return 1 if ($x->{_es} eq '+' # 123.45 is never
- && $MBI->_is_even($x->{_m})); # but 1200 is
- 0;
+ (($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
+ ($x->{_es} eq '+') && # 123.45 isn't
+ ($MBI->_is_even($x->{_m}))) ? 1 : 0; # but 1200 is
}
-sub bmul
+sub bmul
{
- # multiply two numbers -- stolen from Knuth Vol 2 pg 233
- # (BINT or num_str, BINT or num_str) return BINT
+ # multiply two numbers
# set up parameters
- my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);
+ my ($self,$x,$y,@r) = (ref($_[0]),@_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
- ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
+ ($self,$x,$y,@r) = objectify(2,@_);
}
return $x if $x->modify('bmul');
return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
return $x->binf('-');
}
- # handle result = 0
- return $x->bzero() if $x->is_zero() || $y->is_zero();
- return $upgrade->bmul($x,$y,$a,$p,$r) if defined $upgrade &&
+ return $upgrade->bmul($x,$y,@r) if defined $upgrade &&
+ ((!$x->isa($self)) || (!$y->isa($self)));
+
+ # aEb * cEd = (a*c)E(b+d)
+ $MBI->_mul($x->{_m},$y->{_m});
+ ($x->{_e}, $x->{_es}) = _e_add($x->{_e}, $y->{_e}, $x->{_es}, $y->{_es});
+
+ $r[3] = $y; # no push!
+
+ # adjust sign:
+ $x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
+ $x->bnorm->round(@r);
+ }
+
+sub bmuladd
+ {
+ # multiply two numbers and add the third to the result
+
+ # set up parameters
+ my ($self,$x,$y,$z,@r) = (ref($_[0]),@_);
+ # objectify is costly, so avoid it
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+ {
+ ($self,$x,$y,$z,@r) = objectify(3,@_);
+ }
+
+ return $x if $x->modify('bmuladd');
+
+ return $x->bnan() if (($x->{sign} eq $nan) ||
+ ($y->{sign} eq $nan) ||
+ ($z->{sign} eq $nan));
+
+ # inf handling
+ if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
+ {
+ return $x->bnan() if $x->is_zero() || $y->is_zero();
+ # result will always be +-inf:
+ # +inf * +/+inf => +inf, -inf * -/-inf => +inf
+ # +inf * -/-inf => -inf, -inf * +/+inf => -inf
+ return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
+ return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
+ return $x->binf('-');
+ }
+
+ return $upgrade->bmul($x,$y,@r) if defined $upgrade &&
((!$x->isa($self)) || (!$y->isa($self)));
# aEb * cEd = (a*c)E(b+d)
$MBI->_mul($x->{_m},$y->{_m});
($x->{_e}, $x->{_es}) = _e_add($x->{_e}, $y->{_e}, $x->{_es}, $y->{_es});
+ $r[3] = $y; # no push!
+
# adjust sign:
$x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
- return $x->bnorm()->round($a,$p,$r,$y);
+
+ # z=inf handling (z=NaN handled above)
+ $x->{sign} = $z->{sign}, return $x if $z->{sign} =~ /^[+-]inf$/;
+
+ # take lower of the two e's and adapt m1 to it to match m2
+ my $e = $z->{_e};
+ $e = $MBI->_zero() if !defined $e; # if no BFLOAT?
+ $e = $MBI->_copy($e); # make copy (didn't do it yet)
+
+ my $es;
+
+ ($e,$es) = _e_sub($e, $x->{_e}, $z->{_es} || '+', $x->{_es});
+
+ my $add = $MBI->_copy($z->{_m});
+
+ if ($es eq '-') # < 0
+ {
+ $MBI->_lsft( $x->{_m}, $e, 10);
+ ($x->{_e},$x->{_es}) = _e_add($x->{_e}, $e, $x->{_es}, $es);
+ }
+ elsif (!$MBI->_is_zero($e)) # > 0
+ {
+ $MBI->_lsft($add, $e, 10);
+ }
+ # else: both e are the same, so just leave them
+
+ if ($x->{sign} eq $z->{sign})
+ {
+ # add
+ $x->{_m} = $MBI->_add($x->{_m}, $add);
+ }
+ else
+ {
+ ($x->{_m}, $x->{sign}) =
+ _e_add($x->{_m}, $add, $x->{sign}, $z->{sign});
+ }
+
+ # delete trailing zeros, then round
+ $x->bnorm()->round(@r);
}
sub bdiv
$x->round($a,$p,$r,$y);
}
+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} !~ /^[+-]$/;
+
+ # $mod is positive, sign on $exp is ignored, result also positive
+
+ # XXX TODO: speed it up when all three numbers are integers
+ $num->bpow($exp)->bmod($mod);
+ }
+
###############################################################################
# trigonometric functions
# rendundand operations ( like *= 1 ) were removed.
my ($self,$n) = @_;
+ if (@_ == 0)
+ {
+ $self = $class;
+ }
if (@_ == 1)
{
# called like Math::BigFloat::bpi(10);
sub bnorm
{
# adjust m and e so that m is smallest possible
- # round number according to accuracy and precision settings
my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
return $x if $x->{sign} !~ /^[+-]$/; # inf, nan etc
{
if ($MBI->_acmp($x->{_e},$z) >= 0)
{
- $x->{_e} = $MBI->_sub ($x->{_e}, $z);
+ $x->{_e} = $MBI->_sub ($x->{_e}, $z);
$x->{_es} = '+' if $MBI->_is_zero($x->{_e});
}
else
{
- $x->{_e} = $MBI->_sub ( $MBI->_copy($z), $x->{_e});
+ $x->{_e} = $MBI->_sub ( $MBI->_copy($z), $x->{_e});
$x->{_es} = '+';
}
}
else
{
- $x->{_e} = $MBI->_add ($x->{_e}, $z);
+ $x->{_e} = $MBI->_add ($x->{_e}, $z);
}
}
else
$x->bmod($y); # modulus ($x % $y)
$x->bpow($y); # power of arguments ($x ** $y)
+ $x->bmodpow($exp,$mod); # modular exponentation (($num**$exp) % $mod))
$x->blsft($y, $n); # left shift by $y places in base $n
$x->brsft($y, $n); # right shift by $y places in base $n
# returns (quo,rem) or quo if in scalar context
This method was added in v1.87 of Math::BigInt (June 2007).
+=head2 bmuladd()
+
+ $x->bmuladd($y,$z);
+
+Multiply $x by $y, and then add $z to the result.
+
+This method was added in v1.87 of Math::BigInt (June 2007).
+
=head1 Autocreating constants
After C<use Math::BigFloat ':constant'> all the floating point constants
sub bmul
{
- # multiply two numbers -- stolen from Knuth Vol 2 pg 233
+ # multiply the first number by the second numbers
# (BINT or num_str, BINT or num_str) return BINT
# set up parameters
$x->round(@r);
}
+sub bmuladd
+ {
+ # multiply two numbers and then add the third to the result
+ # (BINT or num_str, BINT or num_str, BINT or num_str) return BINT
+
+ # set up parameters
+ my ($self,$x,$y,$z,@r) = (ref($_[0]),@_);
+ # objectify is costly, so avoid it
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+ {
+ ($self,$x,$y,$z,@r) = objectify(3,@_);
+ }
+
+ return $x if $x->modify('bmuladd');
+
+ return $x->bnan() if ($x->{sign} eq $nan) ||
+ ($y->{sign} eq $nan) ||
+ ($z->{sign} eq $nan);
+
+ # inf handling of x and y
+ if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
+ {
+ return $x->bnan() if $x->is_zero() || $y->is_zero();
+ # result will always be +-inf:
+ # +inf * +/+inf => +inf, -inf * -/-inf => +inf
+ # +inf * -/-inf => -inf, -inf * +/+inf => -inf
+ return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
+ return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
+ return $x->binf('-');
+ }
+ # inf handling x*y and z
+ if (($z->{sign} =~ /^[+-]inf$/))
+ {
+ # something +-inf => +-inf
+ $x->{sign} = $z->{sign}, return $x if $z->{sign} =~ /^[+-]inf$/;
+ }
+
+ return $upgrade->bmuladd($x,$upgrade->new($y),$upgrade->new($z),@r)
+ if defined $upgrade && (!$y->isa($self) || !$z->isa($self) || !$x->isa($self));
+
+ # TODO: what it $y and $z have A or P set?
+ $r[3] = $z; # 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
+
+ my ($sx, $sz) = ( $x->{sign}, $z->{sign} ); # get signs
+
+ if ($sx eq $sz)
+ {
+ $x->{value} = $CALC->_add($x->{value},$z->{value}); # same sign, abs add
+ }
+ else
+ {
+ my $a = $CALC->_acmp ($z->{value},$x->{value}); # absolute compare
+ if ($a > 0)
+ {
+ $x->{value} = $CALC->_sub($z->{value},$x->{value},1); # abs sub w/ swap
+ $x->{sign} = $sz;
+ }
+ elsif ($a == 0)
+ {
+ # speedup, if equal, set result to 0
+ $x->{value} = $CALC->_zero();
+ $x->{sign} = '+';
+ }
+ else # a < 0
+ {
+ $x->{value} = $CALC->_sub($x->{value}, $z->{value}); # abs sub
+ }
+ }
+ $x->round(@r);
+ }
+
sub _div_inf
{
# helper function that handles +-inf cases for bdiv()/bmod() to reuse code
sub bmodpow
{
# takes a very large number to a very large exponent in a given very
- # large modulus, quickly, thanks to binary exponentation. supports
+ # large modulus, quickly, thanks to binary exponentation. Supports
# negative exponents.
my ($self,$num,$exp,$mod,@r) = objectify(3,@_);
$x->bdiv($y); # divide, set $x to quotient
# return (quo,rem) or quo if scalar
+ $x->bmuladd($y,$z); # $x = $x * $y + $z
+
$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->bmul($y); # multiplication (multiply $x by $y)
+=head2 bmuladd()
+
+ $x->bmuladd($y,$z);
+
+Multiply $x by $y, and then add $z to the result,
+
+This method was added in v1.87 of Math::BigInt (June 2007).
+
=head2 bdiv()
$x->bdiv($y); # divide, set $x to quotient