summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl/lib/Math/BigFloat.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlperl/lib/Math/BigFloat.pm')
-rw-r--r--Master/tlpkg/tlperl/lib/Math/BigFloat.pm255
1 files changed, 173 insertions, 82 deletions
diff --git a/Master/tlpkg/tlperl/lib/Math/BigFloat.pm b/Master/tlpkg/tlperl/lib/Math/BigFloat.pm
index 27d60b3143c..06a6e48417c 100644
--- a/Master/tlpkg/tlperl/lib/Math/BigFloat.pm
+++ b/Master/tlpkg/tlperl/lib/Math/BigFloat.pm
@@ -12,8 +12,8 @@ package Math::BigFloat;
# _a : accuracy
# _p : precision
-$VERSION = '1.60';
-require 5.006;
+$VERSION = '1.993';
+require 5.006002;
require Exporter;
@ISA = qw/Math::BigInt/;
@@ -60,7 +60,7 @@ $upgrade = undef;
$downgrade = undef;
# the package we are using for our private parts, defaults to:
# Math::BigInt->config()->{lib}
-my $MBI = 'Math::BigInt::FastCalc';
+my $MBI = 'Math::BigInt::Calc';
# are NaNs ok? (otherwise it dies when encountering an NaN) set w/ config()
$_trap_nan = 0;
@@ -149,7 +149,7 @@ sub new
$self->{sign} = $wanted->sign();
return $self->bnorm();
}
- # else: got a string or something maskerading as number (with overload)
+ # else: got a string or something masquerading as number (with overload)
# handle '+inf', '-inf' first
if ($wanted =~ /^[+-]?inf\z/)
@@ -353,7 +353,7 @@ sub config
}
##############################################################################
-# string conversation
+# string conversion
sub bstr
{
@@ -473,6 +473,7 @@ sub bcmp
# set up parameters
my ($self,$x,$y) = (ref($_[0]),@_);
+
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
@@ -482,58 +483,150 @@ sub bcmp
return $upgrade->bcmp($x,$y) if defined $upgrade &&
((!$x->isa($self)) || (!$y->isa($self)));
- if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
- {
- # handle +-inf and NaN
- return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
- return 0 if ($x->{sign} eq $y->{sign}) && ($x->{sign} =~ /^[+-]inf$/);
- return +1 if $x->{sign} eq '+inf';
- return -1 if $x->{sign} eq '-inf';
- return -1 if $y->{sign} eq '+inf';
- return +1;
- }
+ # Handle all 'nan' cases.
- # check sign for speed first
- 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
+ return undef if ($x->{sign} eq $nan) || ($y->{sign} eq $nan);
+
+ # Handle all '+inf' and '-inf' cases.
+
+ return 0 if ($x->{sign} eq '+inf' && $y->{sign} eq '+inf' ||
+ $x->{sign} eq '-inf' && $y->{sign} eq '-inf');
+ return +1 if $x->{sign} eq '+inf'; # x = +inf and y < +inf
+ return -1 if $x->{sign} eq '-inf'; # x = -inf and y > -inf
+ return -1 if $y->{sign} eq '+inf'; # x < +inf and y = +inf
+ return +1 if $y->{sign} eq '-inf'; # x > -inf and y = -inf
+
+ # Handle all cases with opposite signs.
+
+ return +1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # also does 0 <=> -y
+ return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # also does -x <=> 0
+
+ # Handle all remaining zero cases.
- # 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
+ 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
+
+ # Both arguments are now finite, non-zero numbers with the same sign.
+
+ my $cmp;
+
+ # The next step is to compare the exponents, but since each mantissa is an
+ # integer of arbitrary value, the exponents must be normalized by the length
+ # of the mantissas before we can compare them.
+
+ my $mxl = $MBI->_len($x->{_m});
+ my $myl = $MBI->_len($y->{_m});
+
+ # If the mantissas have the same length, there is no point in normalizing the
+ # exponents by the length of the mantissas, so treat that as a special case.
+
+ if ($mxl == $myl) {
+
+ # First handle the two cases where the exponents have different signs.
+
+ if ($x->{_es} eq '+' && $y->{_es} eq '-') {
+ $cmp = +1;
+ }
+
+ elsif ($x->{_es} eq '-' && $y->{_es} eq '+') {
+ $cmp = -1;
+ }
+
+ # Then handle the case where the exponents have the same sign.
+
+ else {
+ $cmp = $MBI->_acmp($x->{_e}, $y->{_e});
+ $cmp = -$cmp if $x->{_es} eq '-';
+ }
+
+ # Adjust for the sign, which is the same for x and y, and bail out if
+ # we're done.
+
+ $cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
+ return $cmp if $cmp;
+
+ }
+
+ # We must normalize each exponent by the length of the corresponding
+ # mantissa. Life is a lot easier if we first make both exponents
+ # non-negative. We do this by adding the same positive value to both
+ # exponent. This is safe, because when comparing the exponents, only the
+ # relative difference is important.
+
+ my $ex;
+ my $ey;
+
+ if ($x->{_es} eq '+') {
+
+ # If the exponent of x is >= 0 and the exponent of y is >= 0, there is no
+ # need to do anything special.
+
+ if ($y->{_es} eq '+') {
+ $ex = $MBI->_copy($x->{_e});
+ $ey = $MBI->_copy($y->{_e});
+ }
+
+ # If the exponent of x is >= 0 and the exponent of y is < 0, add the
+ # absolute value of the exponent of y to both.
+
+ else {
+ $ex = $MBI->_copy($x->{_e});
+ $ex = $MBI->_add($ex, $y->{_e}); # ex + |ey|
+ $ey = $MBI->_zero(); # -ex + |ey| = 0
+ }
+
+ } else {
+
+ # If the exponent of x is < 0 and the exponent of y is >= 0, add the
+ # absolute value of the exponent of x to both.
+
+ if ($y->{_es} eq '+') {
+ $ex = $MBI->_zero(); # -ex + |ex| = 0
+ $ey = $MBI->_copy($y->{_e});
+ $ey = $MBI->_add($ey, $x->{_e}); # ey + |ex|
+ }
+
+ # If the exponent of x is < 0 and the exponent of y is < 0, add the
+ # absolute values of both exponents to both exponents.
+
+ else {
+ $ex = $MBI->_copy($y->{_e}); # -ex + |ey| + |ex| = |ey|
+ $ey = $MBI->_copy($x->{_e}); # -ey + |ex| + |ey| = |ex|
+ }
+
+ }
+
+ # Now we can normalize the exponents by adding lengths of the mantissas.
+
+ $MBI->_add($ex, $MBI->_new($mxl));
+ $MBI->_add($ey, $MBI->_new($myl));
+
+ # We're done if the exponents are different.
+
+ $cmp = $MBI->_acmp($ex, $ey);
+ $cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
+ return $cmp if $cmp;
+
+ # Compare the mantissas, but first normalize them by padding the shorter
+ # mantissa with zeros (shift left) until it has the same length as the longer
+ # mantissa.
+
+ my $mx = $x->{_m};
+ my $my = $y->{_m};
+
+ if ($mxl > $myl) {
+ $my = $MBI->_lsft($MBI->_copy($my), $MBI->_new($mxl - $myl), 10);
+ } elsif ($mxl < $myl) {
+ $mx = $MBI->_lsft($MBI->_copy($mx), $MBI->_new($myl - $mxl), 10);
+ }
+
+ $cmp = $MBI->_acmp($mx, $my);
+ $cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
+ return $cmp;
- # adjust so that exponents are equal
- my $lxm = $MBI->_len($x->{_m});
- my $lym = $MBI->_len($y->{_m});
- # the numify somewhat limits our length, but makes it much faster
- my ($xes,$yes) = (1,1);
- $xes = -1 if $x->{_es} ne '+';
- $yes = -1 if $y->{_es} ne '+';
- my $lx = $lxm + $xes * $MBI->_num($x->{_e});
- my $ly = $lym + $yes * $MBI->_num($y->{_e});
- my $l = $lx - $ly; $l = -$l if $x->{sign} eq '-';
- return $l <=> 0 if $l != 0;
-
- # lengths (corrected by exponent) are equal
- # so make mantissa equal length by padding with zero (shift left)
- my $diff = $lxm - $lym;
- my $xm = $x->{_m}; # not yet copy it
- my $ym = $y->{_m};
- if ($diff > 0)
- {
- $ym = $MBI->_copy($y->{_m});
- $ym = $MBI->_lsft($ym, $MBI->_new($diff), 10);
- }
- elsif ($diff < 0)
- {
- $xm = $MBI->_copy($x->{_m});
- $xm = $MBI->_lsft($xm, $MBI->_new(-$diff), 10);
- }
- my $rc = $MBI->_acmp($xm,$ym);
- $rc = -$rc if $x->{sign} eq '-'; # -124 < -123
- $rc <=> 0;
}
sub bacmp
@@ -1141,7 +1234,7 @@ sub _log
# in case of $x == 1, result is 0
return $x->bzero() if $x->is_one();
- # XXX TODO: rewrite this in a similiar manner to bexp()
+ # XXX TODO: rewrite this in a similar manner to bexp()
# http://www.efunda.com/math/taylor_series/logarithmic.cfm?search_string=log
@@ -1604,12 +1697,7 @@ 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,@_);
- }
+ my ($self,$x,$y,$z,@r) = objectify(3,@_);
return $x if $x->modify('bmuladd');
@@ -1759,7 +1847,7 @@ sub bdiv
$y->{sign} =~ tr/+-/-+/;
# continue with normal div code:
- # make copy of $x in case of list context for later reminder calculation
+ # make copy of $x in case of list context for later remainder calculation
if (wantarray && $y_not_one)
{
$rem = $x->copy();
@@ -1821,7 +1909,7 @@ sub bdiv
sub bmod
{
- # (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return reminder
+ # (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return remainder
# set up parameters
my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);
@@ -2128,7 +2216,7 @@ sub bsqrt
}
# sqrt(2) = 1.4 because sqrt(2*100) = 1.4*10; so we can increase the accuracy
- # of the result by multipyling the input by 100 and then divide the integer
+ # of the result by multiplying the input by 100 and then divide the integer
# result of sqrt(input) by 10. Rounding afterwards returns the real result.
# The following steps will transform 123.456 (in $x) into 123456 (in $y1)
@@ -2408,7 +2496,7 @@ sub bpow
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 exponentiation. Supports
# negative exponents.
my ($self,$num,$exp,$mod,@r) = objectify(3,@_);
@@ -3372,7 +3460,7 @@ sub brsft
# negative amount?
return $x->blsft($y->copy()->babs(),$n) if $y->{sign} =~ /^-/;
- # the following call to bdiv() will return either quo or (quo,reminder):
+ # the following call to bdiv() will return either quo or (quo,remainder):
$x->bdiv($n->bpow($y),$a,$p,$r,$y);
}
@@ -3684,6 +3772,9 @@ sub as_number
$x = $x->can('as_float') ? $x->as_float() : $self->new(0+"$x");
}
+ return Math::BigInt->binf($x->sign()) if $x->is_inf();
+ return Math::BigInt->bnan() if $x->is_nan();
+
my $z = $MBI->_copy($x->{_m});
if ($x->{_es} eq '-') # < 0
{
@@ -3693,7 +3784,7 @@ sub as_number
{
$MBI->_lsft( $z, $x->{_e},10);
}
- $z = Math::BigInt->new( $x->{sign} . $MBI->_num($z));
+ $z = Math::BigInt->new( $x->{sign} . $MBI->_str($z));
$z;
}
@@ -3768,7 +3859,7 @@ Math::BigFloat - Arbitrary size floating point math package
# 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
# necessary when mixing $a = $b assignments with non-overloaded math.
-
+
# set
$x->bzero(); # set $i to 0
$x->bnan(); # set $i to NaN
@@ -3783,7 +3874,7 @@ Math::BigFloat - Arbitrary size floating point math package
$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)
@@ -3792,24 +3883,24 @@ Math::BigFloat - Arbitrary size floating point math package
$x->bmod($y); # modulus ($x % $y)
$x->bpow($y); # power of arguments ($x ** $y)
- $x->bmodpow($exp,$mod); # modular exponentation (($num**$exp) % $mod))
+ $x->bmodpow($exp,$mod); # modular exponentiation (($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
-
+
$x->blog(); # logarithm of $x to base e (Euler's number)
$x->blog($base); # logarithm of $x to base $base (f.i. 2)
$x->bexp(); # calculate e ** $x where e is Euler's number
-
+
$x->band($y); # bit-wise and
$x->bior($y); # bit-wise inclusive or
$x->bxor($y); # bit-wise exclusive or
$x->bnot(); # bit-wise not (two's complement)
-
+
$x->bsqrt(); # calculate square-root
$x->broot($y); # $y'th root of $x (e.g. $y == 3 => cubic root)
$x->bfac(); # factorial of $x (1*2*3*4*..$x)
-
+
$x->bround($N); # accuracy: preserve $N digits
$x->bfround($N); # precision: round to the $Nth digit
@@ -3820,7 +3911,7 @@ Math::BigFloat - Arbitrary size floating point math package
bgcd(@values); # greatest common divisor
blcm(@values); # lowest common multiplicator
-
+
$x->bstr(); # return string
$x->bsstr(); # return string in scientific notation
@@ -3830,7 +3921,7 @@ Math::BigFloat - Arbitrary size floating point math package
$x->parts(); # return (mantissa,exponent) as BigInt
$x->length(); # number of digits (w/o sign and '.')
- ($l,$f) = $x->length(); # number of digits, and length of fraction
+ ($l,$f) = $x->length(); # number of digits, and length of fraction
$x->precision(); # return P of $x (or global, if P of $x undef)
$x->precision($n); # set P of $x to $n
@@ -3905,7 +3996,7 @@ 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.
-Actual math is done by using the class defined with C<with => Class;> (which
+Actual math is done by using the class defined with C<< with => Class; >> (which
defaults to BigInts) to represent the mantissa and exponent.
The sign C</^[+-]$/> is stored separately. The string 'NaN' is used to
@@ -3943,7 +4034,7 @@ Since things like C<sqrt(2)> or C<1 / 3> must presented with a limited
accuracy lest a operation consumes all resources, each operation produces
no more than the requested number of digits.
-If there is no gloabl precision or accuracy set, B<and> the operation in
+If there is no global precision or accuracy set, B<and> the operation in
question was not called with a requested precision or accuracy, B<and> the
input $x has no accuracy or precision set, then a fallback parameter will
be used. For historical reasons, it is called C<div_scale> and can be accessed
@@ -3975,14 +4066,14 @@ It is less confusing to either calculate the result fully, and afterwards
round it explicitly, or use the additional parameters to the math
functions like so:
- use Math::BigFloat;
+ use Math::BigFloat;
$x = Math::BigFloat->new(2);
$y = $x->copy()->bdiv(3);
print $y->bround(5),"\n"; # will give 0.66667
or
- use Math::BigFloat;
+ use Math::BigFloat;
$x = Math::BigFloat->new(2);
$y = $x->copy()->bdiv(3,5); # will give 0.66667
print "$y\n";
@@ -4156,7 +4247,7 @@ This method was added in v1.87 of Math::BigInt (June 2007).
=head2 bmuladd()
- $x->bmuladd($y,$z);
+ $x->bmuladd($y,$z);
Multiply $x by $y, and then add $z to the result.
@@ -4241,7 +4332,7 @@ request a different storage class for use with Math::BigFloat:
use Math::BigFloat with => 'Math::BigInt::Lite';
However, this request is ignored, as the current code now uses the low-level
-math libary for directly storing the number parts.
+math library for directly storing the number parts.
=head1 EXPORTS
@@ -4284,9 +4375,9 @@ The following will probably not print what you expect:
print $c->bdiv(123.456),"\n";
-It prints both quotient and reminder since print works in list context. Also,
+It prints both quotient and remainder since print works in list context. Also,
bdiv() will modify $c, so be careful. You probably want to use
-
+
print $c / 123.456,"\n";
print scalar $c->bdiv(123.456),"\n"; # or if you want to modify $c