summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2002-03-23 20:34:43 +0000
committerJarkko Hietaniemi <jhi@iki.fi>2002-03-23 20:34:43 +0000
commit56b9c9515cd02d944073a40912b99b5ed69f9766 (patch)
treea26b952b32fa1e26f4dfe176dfa14841b8406716 /lib
parent071db25d4bd6237e4ead7e44b9c1420448a117ff (diff)
downloadperl-56b9c9515cd02d944073a40912b99b5ed69f9766.tar.gz
Upgrade to Math::BigInt 1.55, from Tels.
p4raw-id: //depot/perl@15447
Diffstat (limited to 'lib')
-rw-r--r--lib/Math/BigFloat.pm292
-rw-r--r--lib/Math/BigInt.pm99
-rw-r--r--lib/Math/BigInt/Calc.pm10
-rw-r--r--lib/Math/BigInt/t/bare_mbf.t9
-rw-r--r--lib/Math/BigInt/t/bare_mbi.t2
-rw-r--r--lib/Math/BigInt/t/bigfltpm.inc19
-rwxr-xr-xlib/Math/BigInt/t/bigfltpm.t2
-rw-r--r--lib/Math/BigInt/t/bigintpm.inc87
-rwxr-xr-xlib/Math/BigInt/t/bigintpm.t2
-rw-r--r--lib/Math/BigInt/t/config.t2
-rw-r--r--lib/Math/BigInt/t/constant.t13
-rw-r--r--lib/Math/BigInt/t/mbi_rand.t56
-rwxr-xr-xlib/Math/BigInt/t/sub_mbf.t2
-rwxr-xr-xlib/Math/BigInt/t/sub_mbi.t2
-rw-r--r--lib/Math/BigInt/t/upgrade.inc6
-rw-r--r--lib/Math/BigInt/t/upgrade.t2
-rw-r--r--lib/Math/BigInt/t/use_lib1.t24
-rw-r--r--lib/Math/BigInt/t/use_lib2.t24
-rw-r--r--lib/Math/BigInt/t/use_lib3.t24
-rw-r--r--lib/Math/BigInt/t/use_lib4.t25
20 files changed, 602 insertions, 100 deletions
diff --git a/lib/Math/BigFloat.pm b/lib/Math/BigFloat.pm
index ad6588e9bc..d47b5f1f2a 100644
--- a/lib/Math/BigFloat.pm
+++ b/lib/Math/BigFloat.pm
@@ -12,15 +12,16 @@ package Math::BigFloat;
# _p: precision
# _f: flags, used to signal MBI not to touch our private parts
-$VERSION = '1.30';
+$VERSION = '1.31';
require 5.005;
use Exporter;
-use Math::BigInt qw/objectify/;
+use File::Spec;
+# use Math::BigInt;
@ISA = qw( Exporter Math::BigInt);
use strict;
use vars qw/$AUTOLOAD $accuracy $precision $div_scale $round_mode $rnd_mode/;
-use vars qw/$upgrade $downgrade/;
+use vars qw/$upgrade $downgrade $MBI/;
my $class = "Math::BigFloat";
use overload
@@ -48,16 +49,21 @@ $div_scale = 40;
$upgrade = undef;
$downgrade = undef;
+$MBI = 'Math::BigInt'; # the package we are using for our private parts
+ # changable by use Math::BigFloat with => 'package'
##############################################################################
# the old code had $rnd_mode, so we need to support it, too
-$rnd_mode = 'even';
sub TIESCALAR { my ($class) = @_; bless \$round_mode, $class; }
sub FETCH { return $round_mode; }
sub STORE { $rnd_mode = $_[0]->round_mode($_[1]); }
-BEGIN { tie $rnd_mode, 'Math::BigFloat'; }
+BEGIN
+ {
+ $rnd_mode = 'even';
+ tie $rnd_mode, 'Math::BigFloat';
+ }
##############################################################################
@@ -104,7 +110,7 @@ sub new
if ((ref($wanted)) && (ref($wanted) ne $class))
{
$self->{_m} = $wanted->as_number(); # get us a bigint copy
- $self->{_e} = Math::BigInt->bzero();
+ $self->{_e} = $MBI->bzero();
$self->{_m}->babs();
$self->{sign} = $wanted->sign();
return $self->bnorm();
@@ -115,8 +121,8 @@ sub new
{
return $downgrade->new($wanted) if $downgrade;
- $self->{_e} = Math::BigInt->bzero();
- $self->{_m} = Math::BigInt->bzero();
+ $self->{_e} = $MBI->bzero();
+ $self->{_m} = $MBI->bzero();
$self->{sign} = $wanted;
$self->{sign} = '+inf' if $self->{sign} eq 'inf';
return $self->bnorm();
@@ -129,16 +135,16 @@ sub new
return $downgrade->bnan() if $downgrade;
- $self->{_e} = Math::BigInt->bzero();
- $self->{_m} = Math::BigInt->bzero();
+ $self->{_e} = $MBI->bzero();
+ $self->{_m} = $MBI->bzero();
$self->{sign} = $nan;
}
else
{
# make integer from mantissa by adjusting exp, then convert to bigint
# undef,undef to signal MBI that we don't need no bloody rounding
- $self->{_e} = Math::BigInt->new("$$es$$ev",undef,undef); # exponent
- $self->{_m} = Math::BigInt->new("$$miv$$mfv",undef,undef); # create mant.
+ $self->{_e} = $MBI->new("$$es$$ev",undef,undef); # exponent
+ $self->{_m} = $MBI->new("$$miv$$mfv",undef,undef); # create mant.
# 3.123E0 = 3123E-3, and 3.123E-2 => 3123E-5
$self->{_e} -= CORE::length($$mfv) if CORE::length($$mfv) != 0;
$self->{sign} = $$mis;
@@ -163,39 +169,39 @@ sub _bnan
{
# used by parent class bone() to initialize number to 1
my $self = shift;
- $self->{_m} = Math::BigInt->bzero();
- $self->{_e} = Math::BigInt->bzero();
+ $self->{_m} = $MBI->bzero();
+ $self->{_e} = $MBI->bzero();
}
sub _binf
{
# used by parent class bone() to initialize number to 1
my $self = shift;
- $self->{_m} = Math::BigInt->bzero();
- $self->{_e} = Math::BigInt->bzero();
+ $self->{_m} = $MBI->bzero();
+ $self->{_e} = $MBI->bzero();
}
sub _bone
{
# used by parent class bone() to initialize number to 1
my $self = shift;
- $self->{_m} = Math::BigInt->bone();
- $self->{_e} = Math::BigInt->bzero();
+ $self->{_m} = $MBI->bone();
+ $self->{_e} = $MBI->bzero();
}
sub _bzero
{
# used by parent class bone() to initialize number to 1
my $self = shift;
- $self->{_m} = Math::BigInt->bzero();
- $self->{_e} = Math::BigInt->bone();
+ $self->{_m} = $MBI->bzero();
+ $self->{_e} = $MBI->bone();
}
sub isa
{
my ($self,$class) = @_;
- return if $class eq 'Math::BigInt'; # we aren't
- return UNIVERSAL::isa($self,$class);
+ return if $class =~ /^Math::BigInt/; # we aren't one of these
+ UNIVERSAL::isa($self,$class);
}
##############################################################################
@@ -264,7 +270,7 @@ sub bstr
my $zeros = -$x->{_p} + $cad;
$es .= $dot.'0' x $zeros if $zeros > 0;
}
- return $es;
+ $es;
}
sub bsstr
@@ -285,7 +291,7 @@ sub bsstr
}
my $sign = $x->{_e}->{sign}; $sign = '' if $sign eq '-';
my $sep = 'e'.$sign;
- return $x->{_m}->bstr().$sep.$x->{_e}->bstr();
+ $x->{_m}->bstr().$sep.$x->{_e}->bstr();
}
sub numify
@@ -293,7 +299,7 @@ sub numify
# Make a number from a BigFloat object
# simple return string and let Perl's atoi()/atof() handle the rest
my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
- return $x->bsstr();
+ $x->bsstr();
}
##############################################################################
@@ -429,8 +435,7 @@ sub badd
return $x if $x->{sign} eq $y->{sign};
return $x->bnan();
}
- # +-inf + something => +inf
- # something +-inf => +-inf
+ # +-inf + something => +inf; something +-inf => +-inf
$x->{sign} = $y->{sign}, return $x if $y->{sign} =~ /^[+-]inf$/;
return $x;
}
@@ -448,11 +453,10 @@ sub badd
# take lower of the two e's and adapt m1 to it to match m2
my $e = $y->{_e};
- $e = Math::BigInt::bzero() if !defined $e; # if no BFLOAT ?
- $e = $e->copy(); # make copy (didn't do it yet)
+ $e = $MBI->bzero() if !defined $e; # if no BFLOAT ?
+ $e = $e->copy(); # make copy (didn't do it yet)
$e->bsub($x->{_e});
my $add = $y->{_m}->copy();
-# if ($e < 0) # < 0
if ($e->{sign} eq '-') # < 0
{
my $e1 = $e->copy()->babs();
@@ -460,7 +464,6 @@ sub badd
$x->{_m}->blsft($e1,10);
$x->{_e} += $e; # need the sign of e
}
-# if ($e > 0) # > 0
elsif (!$e->is_zero()) # > 0
{
#$add *= (10 ** $e);
@@ -947,13 +950,12 @@ sub bmod
{
$x->{_m}->blsft($x->{_e},10);
}
- $x->{_e} = Math::BigInt->bzero() unless $x->{_e}->is_zero();
+ $x->{_e} = $MBI->bzero() unless $x->{_e}->is_zero();
$x->{_e}->bsub($shiftx) if $shiftx != 0;
$x->{_e}->bsub($shifty) if $shifty != 0;
# now mantissas are equalized, exponent of $x is adjusted, so calc result
-# $ym->{sign} = '-' if $neg; # bmod() will make the correction for us
$x->{_m}->bmod($ym);
@@ -1023,7 +1025,7 @@ sub bsqrt
&& ($xas->bacmp($gs * $gs) == 0)) # guess hit the nail on the head?
{
# exact result
- $x->{_m} = $gs; $x->{_e} = Math::BigInt->bzero(); $x->bnorm();
+ $x->{_m} = $gs; $x->{_e} = $MBI->bzero(); $x->bnorm();
# shortcut to not run trough _find_round_parameters again
if (defined $params[1])
{
@@ -1104,6 +1106,108 @@ sub bfac
$x->bnorm()->round(@r);
}
+sub _pow2
+ {
+ # Calculate a power where $y is a non-integer, like 2 ** 0.5
+ my ($x,$y,$a,$p,$r) = @_;
+ my $self = ref($x);
+
+ # we need to limit the accuracy to protect against overflow
+ my $fallback = 0;
+ my $scale = 0;
+ my @params = $x->_find_round_parameters($a,$p,$r);
+
+ # no rounding at all, so must use fallback
+ if (scalar @params == 1)
+ {
+ # simulate old behaviour
+ $params[1] = $self->div_scale(); # and round to it as accuracy
+ $scale = $params[1]+4; # at least four more for proper round
+ $params[3] = $r; # round mode by caller or undef
+ $fallback = 1; # to clear a/p afterwards
+ }
+ else
+ {
+ # the 4 below is empirical, and there might be cases where it is not
+ # enough...
+ $scale = abs($params[1] || $params[2]) + 4; # take whatever is defined
+ }
+
+ # when user set globals, they would interfere with our calculation, so
+ # disable then and later re-enable them
+ no strict 'refs';
+ my $abr = "$self\::accuracy"; my $ab = $$abr; $$abr = undef;
+ my $pbr = "$self\::precision"; my $pb = $$pbr; $$pbr = undef;
+ # we also need to disable any set A or P on $x (_find_round_parameters took
+ # them already into account), since these would interfere, too
+ delete $x->{_a}; delete $x->{_p};
+ # need to disable $upgrade in BigInt, to avoid deep recursion
+ local $Math::BigInt::upgrade = undef;
+
+ # split the second argument into its integer and fraction part
+ # we calculate the result then from these two parts, like in
+ # 2 ** 2.4 == (2 ** 2) * (2 ** 0.4)
+ my $c = $self->new($y->as_number()); # integer part
+ my $d = $y-$c; # fractional part
+ my $xc = $x->copy(); # a temp. copy
+
+ # now calculate binary fraction from the decimal fraction on the fly
+ # f.i. 0.654:
+ # 0.654 * 2 = 1.308 > 1 => 0.1 ( 1.308 - 1 = 0.308)
+ # 0.308 * 2 = 0.616 < 1 => 0.10
+ # 0.616 * 2 = 1.232 > 1 => 0.101 ( 1.232 - 1 = 0.232)
+ # and so on...
+ # The process stops when the result is exactly one, or when we have
+ # enough accuracy
+
+ # From the binary fraction we calculate the result as follows:
+ # we assume the fraction ends in 1, and we remove this one first.
+ # For each digit after the dot, assume 1 eq R and 0 eq XR, where R means
+ # take square root and X multiply with the original X.
+
+ my $i = 0;
+ while ($i++ < 50)
+ {
+ $d->badd($d); # * 2
+ last if $d->is_one(); # == 1
+ $x->bsqrt(); # 0
+ if ($d > 1)
+ {
+ $x->bsqrt(); $x->bmul($xc); $d->bdec(); # 1
+ }
+ print "at $x\n";
+ }
+ # assume fraction ends in 1
+ $x->bsqrt(); # 1
+ if (!$c->is_one())
+ {
+ $x->bmul( $xc->bpow($c) );
+ }
+ elsif (!$c->is_zero())
+ {
+ $x->bmul( $xc );
+ }
+ # done
+
+ # shortcut to not run trough _find_round_parameters again
+ if (defined $params[1])
+ {
+ $x->bround($params[1],$params[3]); # then round accordingly
+ }
+ else
+ {
+ $x->bfround($params[2],$params[3]); # then round accordingly
+ }
+ if ($fallback)
+ {
+ # clear a/p after round, since user did not request it
+ $x->{_a} = undef; $x->{_p} = undef;
+ }
+ # restore globals
+ $$abr = $ab; $$pbr = $pb;
+ $x;
+ }
+
sub _pow
{
# Calculate a power where $y is a non-integer, like 2 ** 0.5
@@ -1209,7 +1313,7 @@ sub bpow
return $x->bone() if $y->is_zero();
return $x if $x->is_one() || $y->is_one();
- return $x->_pow($y,$a,$p,$r) if !$y->is_int(); # non-integer power
+ return $x->_pow2($y,$a,$p,$r) if !$y->is_int(); # non-integer power
my $y1 = $y->as_number(); # make bigint
# if ($x == -1)
@@ -1494,7 +1598,7 @@ sub AUTOLOAD
}
# try one level up, but subst. bxxx() for fxxx() since MBI only got bxxx()
$name =~ s/^f/b/;
- return &{'Math::BigInt'."::$name"}(@_);
+ return &{"$MBI"."::$name"}(@_);
}
my $bname = $name; $bname =~ s/^f/b/;
*{$class."::$name"} = \&$bname;
@@ -1552,6 +1656,7 @@ sub import
{
my $self = shift;
my $l = scalar @_; my $j = 0; my @a = @_;
+ my $lib = '';
for ( my $i = 0; $i < $l ; $i++, $j++)
{
if ( $_[$i] eq ':constant' )
@@ -1575,7 +1680,28 @@ sub import
my $s = 2; $s = 1 if @a-$j < 2; # avoid "can not modify non-existant..."
splice @a, $j, $s; $j -= $s;
}
+ elsif ($_[$i] eq 'lib')
+ {
+ $lib = $_[$i+1] || ''; # default Calc
+ my $s = 2; $s = 1 if @a-$j < 2; # avoid "can not modify non-existant..."
+ splice @a, $j, $s; $j -= $s;
+ }
+ elsif ($_[$i] eq 'with')
+ {
+ $MBI = $_[$i+1] || 'Math::BigInt'; # default Math::BigInt
+ my $s = 2; $s = 1 if @a-$j < 2; # avoid "can not modify non-existant..."
+ splice @a, $j, $s; $j -= $s;
+ }
}
+ my @parts = split /::/, $MBI; # Math::BigInt => Math BigInt
+ my $file = pop @parts; $file .= '.pm'; # BigInt => BigInt.pm
+ $file = File::Spec->catdir (@parts, $file);
+ # let use Math::BigInt lib => 'GMP'; use Math::BigFloat; still work
+ my $mbilib = eval { Math::BigInt->config()->{lib} };
+ $lib .= ",$mbilib" if defined $mbilib;
+ require $file;
+ $MBI->import ( lib => $lib, 'objectify' );
+
# any non :constant stuff is handled by our parent, Exporter
# even if @_ is empty, to give it a chance
$self->SUPER::import(@a); # for subclasses
@@ -1643,7 +1769,7 @@ sub length
$len += $x->{_e} if $x->{_e}->sign() eq '+';
if (wantarray())
{
- my $t = Math::BigInt::bzero();
+ my $t = $MBI->bzero();
$t = $x->{_e}->copy()->babs() if $x->{_e}->sign() eq '-';
return ($len,$t);
}
@@ -1922,10 +2048,100 @@ In particular
perl -MMath::BigFloat=:constant -e 'print 2E-100,"\n"'
-prints the value of C<2E-100>. Note that without conversion of
+prints the value of C<2E-100>. Note that without conversion of
constants the expression 2E-100 will be calculated as normal floating point
number.
+Please note that ':constant' does not affect integer constants, nor binary
+nor hexadecimal constants. Use L<bignum> or L<Math::BigInt> to get this to
+work.
+
+=head2 Math library
+
+Math with the numbers is done (by default) by a module called
+Math::BigInt::Calc. This is equivalent to saying:
+
+ use Math::BigFloat lib => 'Calc';
+
+You can change this by using:
+
+ use Math::BigFloat lib => 'BitVect';
+
+The following would first try to find Math::BigInt::Foo, then
+Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
+
+ use Math::BigFloat lib => 'Foo,Math::BigInt::Bar';
+
+Calc.pm uses as internal format an array of elements of some decimal base
+(usually 1e7, but this might be differen for some systems) with the least
+significant digit first, while BitVect.pm uses a bit vector of base 2, most
+significant bit first. Other modules might use even different means of
+representing the numbers. See the respective module documentation for further
+details.
+
+Please note that Math::BigFloat does B<not> use the denoted library itself,
+but it merely passes the lib argument to Math::BigInt. So, instead of the need
+to do:
+
+ use Math::BigInt lib => 'GMP';
+ use Math::BigFloat;
+
+you can roll it all into one line:
+
+ use Math::BigFloat lib => 'GMP';
+
+Use the lib, Luke! And see L<Using Math::BigInt::Lite> for more details.
+
+=head2 Using Math::BigInt::Lite
+
+It is possible to use L<Math::BigInt::Lite> with Math::BigFloat:
+
+ # 1
+ use Math::BigFloat with => 'Math::BigInt::Lite';
+
+There is no need to "use Math::BigInt" or "use Math::BigInt::Lite", but you
+can combine these if you want. For instance, you may want to use
+Math::BigInt objects in your main script, too.
+
+ # 2
+ use Math::BigInt;
+ use Math::BigFloat with => 'Math::BigInt::Lite';
+
+Of course, you can combine this with the C<lib> parameter.
+
+ # 3
+ use Math::BigFloat with => 'Math::BigInt::Lite', lib => 'GMP,Pari';
+
+If you want to use Math::BigInt's, too, simple add a Math::BigInt B<before>:
+
+ # 4
+ use Math::BigInt;
+ use Math::BigFloat with => 'Math::BigInt::Lite', lib => 'GMP,Pari';
+
+Notice that the module with the last C<lib> will "win" and thus
+it's lib will be used if the lib is available:
+
+ # 5
+ use Math::BigInt lib => 'Bar,Baz';
+ use Math::BigFloat with => 'Math::BigInt::Lite', lib => 'Foo';
+
+That would try to load Foo, Bar, Baz and Calc (in that order). Or in other
+words, Math::BigFloat will try to retain previously loaded libs when you
+don't specify it one.
+
+Actually, the lib loading order would be "Bar,Baz,Calc", and then
+"Foo,Bar,Baz,Calc", but independend of which lib exists, the result is the
+same as trying the latter load alone, except for the fact that Bar or Baz
+might be loaded needlessly in an intermidiate step
+
+The old way still works though:
+
+ # 6
+ use Math::BigInt lib => 'Bar,Baz';
+ use Math::BigFloat;
+
+But B<examples #3 and #4 are recommended> for usage.
+
=head1 BUGS
=over 2
diff --git a/lib/Math/BigInt.pm b/lib/Math/BigInt.pm
index abe2c829b8..3c142f2b6a 100644
--- a/lib/Math/BigInt.pm
+++ b/lib/Math/BigInt.pm
@@ -18,7 +18,7 @@ package Math::BigInt;
my $class = "Math::BigInt";
require 5.005;
-$VERSION = '1.54';
+$VERSION = '1.55';
use Exporter;
@ISA = qw( Exporter );
@EXPORT_OK = qw( objectify _swap bgcd blcm);
@@ -535,7 +535,7 @@ sub binf
# 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))
{
@@ -554,7 +554,8 @@ sub binf
# otherwise do our own thing
$self->{value} = $CALC->_zero();
}
- $self->{sign} = $sign.'inf';
+ $sign = $sign . 'inf' if $sign !~ /inf$/; # - => -inf
+ $self->{sign} = $sign;
($self->{_a},$self->{_p}) = @_; # take over requested rounding
return $self;
}
@@ -657,7 +658,7 @@ 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,@_);
-
+
if ($x->{sign} !~ /^[+-]$/)
{
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
@@ -870,12 +871,11 @@ sub bcmp
# 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 '+';
+ # $x && $y both < 0
$CALC->_acmp($y->{value},$x->{value}); # swaped (lib does only 0,1,-1)
}
@@ -906,8 +906,8 @@ sub 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));
+ return $upgrade->badd($x,$y,@r) if defined $upgrade &&
+ ((ref($x) eq $upgrade) || (ref($y) eq $upgrade));
# print "still badd\n";
$r[3] = $y; # no push!
@@ -1487,7 +1487,7 @@ sub bpow
$x->bmul($x);
}
$x->bmul($pow2) unless $pow2->is_one();
- return $x->round(@r);
+ $x->round(@r);
}
sub blsft
@@ -1716,10 +1716,10 @@ 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,@_);
+ $n = 0 if !defined $n;
- return $CALC->_digit($x->{value},$n);
+ $CALC->_digit($x->{value},$n);
}
sub _trailing_zeros
@@ -1789,7 +1789,7 @@ sub exponent
my $e = $class->bzero();
return $e->binc() if $x->is_zero();
$e += $x->_trailing_zeros();
- return $e;
+ $e;
}
sub mantissa
@@ -1804,8 +1804,9 @@ sub mantissa
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 /= 10 ** $zeros if $zeros != 0;
+ $m;
}
sub parts
@@ -2153,6 +2154,7 @@ sub import
{
# this causes overlord er load to step in
overload::constant integer => sub { $self->new(shift) };
+ overload::constant binary => sub { $self->new(shift) };
splice @a, $j, 1; $j --;
}
elsif ($_[$i] eq 'upgrade')
@@ -2711,35 +2713,60 @@ If used on an object, it will set it to one:
$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
@@ -3381,15 +3408,15 @@ Examples for converting:
=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,
@@ -3413,6 +3440,16 @@ Without the quotes Perl would convert the large number to a floating point
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
diff --git a/lib/Math/BigInt/Calc.pm b/lib/Math/BigInt/Calc.pm
index de4f46ea7e..a7110c9fcf 100644
--- a/lib/Math/BigInt/Calc.pm
+++ b/lib/Math/BigInt/Calc.pm
@@ -8,7 +8,7 @@ require Exporter;
use vars qw/@ISA $VERSION/;
@ISA = qw(Exporter);
-$VERSION = '0.25';
+$VERSION = '0.26';
# Package to store unsigned big integers in decimal and do math with them
@@ -392,7 +392,7 @@ sub _sub
{
# (ref to int_num_array, ref to int_num_array, swap)
# subtract base 1eX numbers -- stolen from Knuth Vol 2 pg 232, $x > $y
- # subtract Y from X (X is always greater/equal!) by modifying x in place
+ # subtract Y from X by modifying x in place
my ($c,$sx,$sy,$s) = @_;
my $car = 0; my $i; my $j = 0;
@@ -410,7 +410,9 @@ sub _sub
#print "case 1 (swap)\n";
for $i (@$sx)
{
- last unless defined $sy->[$j] || $car;
+ # we can't do an early out if $x is than $y, since we
+ # need to copy the high chunks from $y. Found by Bob Mathews.
+ #last unless defined $sy->[$j] || $car;
$sy->[$j] += $BASE
if $car = (($sy->[$j] = $i-($sy->[$j]||0) - $car) < 0);
$j++;
@@ -1174,7 +1176,7 @@ sub _rsft
$dst++;
}
splice (@$x,$dst) if $dst > 0; # kill left-over array elems
- pop @$x if $x->[-1] == 0; # kill last element if 0
+ pop @$x if $x->[-1] == 0 && @$x > 1; # kill last element if 0
} # else rem == 0
$x;
}
diff --git a/lib/Math/BigInt/t/bare_mbf.t b/lib/Math/BigInt/t/bare_mbf.t
index 8288d2b189..abeb8c257c 100644
--- a/lib/Math/BigInt/t/bare_mbf.t
+++ b/lib/Math/BigInt/t/bare_mbf.t
@@ -26,11 +26,14 @@ BEGIN
}
print "# INC = @INC\n";
- plan tests => 1592;
+ plan tests => 1601;
}
-use Math::BigInt lib => 'BareCalc';
-use Math::BigFloat;
+#use Math::BigInt lib => 'BareCalc';
+#use Math::BigFloat;
+
+# use Math::BigInt; use Math::BigFloat lib => 'BareCalc';
+use Math::BigFloat lib => 'BareCalc';
use vars qw ($class $try $x $y $f @args $ans $ans1 $ans1_str $setup $CL);
$class = "Math::BigFloat";
diff --git a/lib/Math/BigInt/t/bare_mbi.t b/lib/Math/BigInt/t/bare_mbi.t
index d480062338..5899dfe03b 100644
--- a/lib/Math/BigInt/t/bare_mbi.t
+++ b/lib/Math/BigInt/t/bare_mbi.t
@@ -26,7 +26,7 @@ BEGIN
}
print "# INC = @INC\n";
- plan tests => 2147;
+ plan tests => 2237;
}
use Math::BigInt lib => 'BareCalc';
diff --git a/lib/Math/BigInt/t/bigfltpm.inc b/lib/Math/BigInt/t/bigfltpm.inc
index 8748d2332f..734b935168 100644
--- a/lib/Math/BigInt/t/bigfltpm.inc
+++ b/lib/Math/BigInt/t/bigfltpm.inc
@@ -153,6 +153,19 @@ $x = $class->new(2); $x->fzero(); ok_undef ($x->{_a}); ok_undef ($x->{_p});
$x = $class->new(2); $x->finf(); ok_undef ($x->{_a}); ok_undef ($x->{_p});
$x = $class->new(2); $x->fone(); ok_undef ($x->{_a}); ok_undef ($x->{_p});
$x = $class->new(2); $x->fnan(); ok_undef ($x->{_a}); ok_undef ($x->{_p});
+
+###############################################################################
+# bone/binf etc as plain calls (Lite failed them)
+
+ok ($class->fzero(),0);
+ok ($class->fone(),1);
+ok ($class->fone('+'),1);
+ok ($class->fone('-'),-1);
+ok ($class->fnan(),'NaN');
+ok ($class->finf(),'inf');
+ok ($class->finf('+'),'inf');
+ok ($class->finf('-'),'-inf');
+ok ($class->finf('-inf'),'-inf');
###############################################################################
# fsqrt() with set global A/P or A/P enabled on $x, also a test whether fsqrt()
@@ -370,7 +383,11 @@ abc:123.456:NaN
# 2 ** 0.5 == sqrt(2)
# 1.41..7 and not 1.4170 since fallback (bsqrt(9) is '3', not 3.0...0)
2:0.5:1.41421356237309504880168872420969807857
-2:0.2:1.148698354997035006798626946777927589444
+#2:0.2:1.148698354997035006798626946777927589444
+6:1.5:14.6969384566990685891837044482353483518
+$div_scale = 20;
+#62.5:12.5:26447206647554886213592.3959144
+$div_scale = 40;
&fneg
fnegNaN:NaN
+inf:-inf
diff --git a/lib/Math/BigInt/t/bigfltpm.t b/lib/Math/BigInt/t/bigfltpm.t
index 2b4f83ac89..a3c0131c15 100755
--- a/lib/Math/BigInt/t/bigfltpm.t
+++ b/lib/Math/BigInt/t/bigfltpm.t
@@ -26,7 +26,7 @@ BEGIN
}
print "# INC = @INC\n";
- plan tests => 1592;
+ plan tests => 1601;
}
use Math::BigInt;
diff --git a/lib/Math/BigInt/t/bigintpm.inc b/lib/Math/BigInt/t/bigintpm.inc
index 39f4c7756e..2bcf3466fb 100644
--- a/lib/Math/BigInt/t/bigintpm.inc
+++ b/lib/Math/BigInt/t/bigintpm.inc
@@ -164,7 +164,7 @@ while (<DATA>)
}elsif ($f eq "bpow"){
$try .= "\$x ** \$y;";
}elsif ($f eq "digit"){
- $try = "\$x = $class->new('$args[0]'); \$x->digit($args[1]);";
+ $try .= "\$x->digit(\$y);";
} else { warn "Unknown op '$f'"; }
} # end else all other ops
@@ -311,25 +311,25 @@ $x = Math::BigInt->new(0); if (!$x) { ok (1,1); } else { ok($x,'to be false') }
@args = Math::BigInt::objectify(2,4,5);
ok (scalar @args,3); # $class, 4, 5
-ok ($args[0],$class);
+ok ($args[0] =~ /^Math::BigInt/);
ok ($args[1],4);
ok ($args[2],5);
@args = Math::BigInt::objectify(0,4,5);
ok (scalar @args,3); # $class, 4, 5
-ok ($args[0],$class);
+ok ($args[0] =~ /^Math::BigInt/);
ok ($args[1],4);
ok ($args[2],5);
@args = Math::BigInt::objectify(2,4,5);
ok (scalar @args,3); # $class, 4, 5
-ok ($args[0],$class);
+ok ($args[0] =~ /^Math::BigInt/);
ok ($args[1],4);
ok ($args[2],5);
@args = Math::BigInt::objectify(2,4,5,6,7);
ok (scalar @args,5); # $class, 4, 5, 6, 7
-ok ($args[0],$class);
+ok ($args[0] =~ /^Math::BigInt/);
ok ($args[1],4); ok (ref($args[1]),$args[0]);
ok ($args[2],5); ok (ref($args[2]),$args[0]);
ok ($args[3],6); ok (ref($args[3]),'');
@@ -446,6 +446,11 @@ if ($x > $BASE) { ok (1,1) } else { ok ("$x > $BASE","$x < $BASE"); }
$x = $class->new($MAX); ok ($x->length(), length($MAX));
###############################################################################
+# test bug that $class->digit($string) did not work
+
+ok ($class->digit(123,2),1);
+
+###############################################################################
# bug in sub where number with at least 6 trailing zeros after any op failed
$x = $class->new(123456); $z = $class->new(10000); $z *= 10; $x -= $z;
@@ -490,6 +495,19 @@ $x = $class->new('-322056000'); ($x,$y) = $x->bdiv('-12882240');
ok ($y,'0'); is_valid($y); # $y not '-0'
###############################################################################
+# bone/binf etc as plain calls (Lite failed them)
+
+ok ($class->bzero(),0);
+ok ($class->bone(),1);
+ok ($class->bone('+'),1);
+ok ($class->bone('-'),-1);
+ok ($class->bnan(),'NaN');
+ok ($class->binf(),'inf');
+ok ($class->binf('+'),'inf');
+ok ($class->binf('-'),'-inf');
+ok ($class->binf('-inf'),'-inf');
+
+###############################################################################
# all tests done
1;
@@ -515,15 +533,20 @@ sub is_valid
my ($x,$f) = @_;
my $e = 0; # error?
- # ok as reference?
- $e = 'Not a reference to Math::BigInt' if !ref($x);
- # has ok sign?
- $e = "Illegal sign $x->{sign} (expected: '+', '-', '-inf', '+inf' or 'NaN'"
- if $e eq '0' && $x->{sign} !~ /^(\+|-|\+inf|-inf|NaN)$/;
+ # allow the check to pass for all Lite, and all MBI and subclasses
+ # ok as reference?
+ $e = 'Not a reference to Math::BigInt' if ref($x) !~ /^Math::BigInt/;
- $e = "-0 is invalid!" if $e ne '0' && $x->{sign} eq '-' && $x == 0;
- $e = $CALC->_check($x->{value}) if $e eq '0';
+ if (ref($x) ne 'Math::BigInt::Lite')
+ {
+ # has ok sign?
+ $e = "Illegal sign $x->{sign} (expected: '+', '-', '-inf', '+inf' or 'NaN'"
+ if $e eq '0' && $x->{sign} !~ /^(\+|-|\+inf|-inf|NaN)$/;
+
+ $e = "-0 is invalid!" if $e ne '0' && $x->{sign} eq '-' && $x == 0;
+ $e = $CALC->_check($x->{value}) if $e eq '0';
+ }
# test done, see if error did crop up
ok (1,1), return if ($e eq '0');
@@ -1029,6 +1052,26 @@ baddNaN:+inf:NaN
-123456789:987654321:864197532
-123456789:-987654321:-1111111110
+123456789:-987654321:-864197532
+-1:10001:10000
+-1:100001:100000
+-1:1000001:1000000
+-1:10000001:10000000
+-1:100000001:100000000
+-1:1000000001:1000000000
+-1:10000000001:10000000000
+-1:100000000001:100000000000
+-1:1000000000001:1000000000000
+-1:10000000000001:10000000000000
+-1:-10001:-10002
+-1:-100001:-100002
+-1:-1000001:-1000002
+-1:-10000001:-10000002
+-1:-100000001:-100000002
+-1:-1000000001:-1000000002
+-1:-10000000001:-10000000002
+-1:-100000000001:-100000000002
+-1:-1000000000001:-1000000000002
+-1:-10000000000001:-10000000000002
&bsub
abc:abc:NaN
abc:+0:NaN
@@ -1071,6 +1114,26 @@ abc:+0:NaN
-123456789:+987654321:-1111111110
-123456789:-987654321:864197532
+123456789:-987654321:1111111110
+10001:1:10000
+100001:1:100000
+1000001:1:1000000
+10000001:1:10000000
+100000001:1:100000000
+1000000001:1:1000000000
+10000000001:1:10000000000
+100000000001:1:100000000000
+1000000000001:1:1000000000000
+10000000000001:1:10000000000000
+10001:-1:10002
+100001:-1:100002
+1000001:-1:1000002
+10000001:-1:10000002
+100000001:-1:100000002
+1000000001:-1:1000000002
+10000000001:-1:10000000002
+100000000001:-1:100000000002
+1000000000001:-1:1000000000002
+10000000000001:-1:10000000000002
&bmul
abc:abc:NaN
abc:+0:NaN
diff --git a/lib/Math/BigInt/t/bigintpm.t b/lib/Math/BigInt/t/bigintpm.t
index eca2d29701..c14d4415ef 100755
--- a/lib/Math/BigInt/t/bigintpm.t
+++ b/lib/Math/BigInt/t/bigintpm.t
@@ -10,7 +10,7 @@ BEGIN
my $location = $0; $location =~ s/bigintpm.t//;
unshift @INC, $location; # to locate the testing files
chdir 't' if -d 't';
- plan tests => 2147;
+ plan tests => 2237;
}
use Math::BigInt;
diff --git a/lib/Math/BigInt/t/config.t b/lib/Math/BigInt/t/config.t
index fc3e52f594..db0c27ef80 100644
--- a/lib/Math/BigInt/t/config.t
+++ b/lib/Math/BigInt/t/config.t
@@ -22,7 +22,7 @@ my $cfg = Math::BigInt->config();
ok (ref($cfg),'HASH');
ok ($cfg->{lib},'Math::BigInt::Calc');
-ok ($cfg->{lib_version},'0.25');
+ok ($cfg->{lib_version},'0.26');
ok ($cfg->{class},'Math::BigInt');
ok ($cfg->{upgrade}||'','');
ok ($cfg->{div_scale},40);
diff --git a/lib/Math/BigInt/t/constant.t b/lib/Math/BigInt/t/constant.t
index ef3e223c1b..3c9b13fd46 100644
--- a/lib/Math/BigInt/t/constant.t
+++ b/lib/Math/BigInt/t/constant.t
@@ -8,13 +8,24 @@ BEGIN
$| = 1;
chdir 't' if -d 't';
unshift @INC, '../lib'; # for running manually
- plan tests => 5;
+ plan tests => 7;
}
use Math::BigInt ':constant';
ok (2 ** 255,'57896044618658097711785492504343953926634992332820282019728792003956564819968');
+{
+ no warnings 'portable';
+ # hexadecimal constants
+ ok (0x123456789012345678901234567890,
+ Math::BigInt->new('0x123456789012345678901234567890'));
+ # binary constants
+ ok (0b01010100011001010110110001110011010010010110000101101101,
+ Math::BigInt->new(
+ '0b01010100011001010110110001110011010010010110000101101101'));
+}
+
use Math::BigFloat ':constant';
ok (1.0 / 3.0, '0.3333333333333333333333333333333333333333');
diff --git a/lib/Math/BigInt/t/mbi_rand.t b/lib/Math/BigInt/t/mbi_rand.t
new file mode 100644
index 0000000000..1f19c6b82b
--- /dev/null
+++ b/lib/Math/BigInt/t/mbi_rand.t
@@ -0,0 +1,56 @@
+#!/usr/bin/perl -w
+
+use Test;
+use strict;
+
+my $count;
+
+BEGIN
+ {
+ $| = 1;
+ unshift @INC, '../lib'; # for running manually
+ my $location = $0; $location =~ s/mbi_rand.t//;
+ unshift @INC, $location; # to locate the testing files
+ chdir 't' if -d 't';
+ $count = 500;
+ plan tests => $count*2;
+ }
+
+use Math::BigInt;
+my $c = 'Math::BigInt';
+
+my $length = 200;
+
+# If you get a failure here, please re-run the test with the printed seed
+# value as input: perl t/mbi_rand.t seed
+
+my $seed = int(rand(65537)); print "# seed: $seed\n"; srand($seed);
+
+my ($A,$B,$ADB,$AMB,$la,$lb);
+for (my $i = 0; $i < $count; $i++)
+ {
+ # length of A and B
+ $la = int(rand($length)+1); $lb = int(rand($length)+1);
+ $A = ''; $B = '';
+ # we create the numbers from "patterns", e.g. get a random number and a
+ # random count and string them together. This means things like
+ # "100000999999999999911122222222" are much more likely. If we just strung
+ # together digits, we would end up with "1272398823211223" etc.
+ while (length($A) < $la) { $A .= int(rand(100)) x int(rand(16)); }
+ while (length($B) < $lb) { $B .= int(rand(100)) x int(rand(16)); }
+ $A = $c->new($A); $B = $c->new($B);
+ print "# A $A\n# B $B\n";
+ if ($A->is_zero() || $B->is_zero())
+ {
+ ok (1,1); ok (1,1); next;
+ }
+ # check that int(A/B)*B + A % B == A holds for all inputs
+ # $X = ($A/$B)*$B + 2 * ($A % $B) - ($A % $B);
+ ($ADB,$AMB) = $A->copy()->bdiv($B);
+ ok ($A,$ADB*$B+2*$AMB-$AMB);
+ # swap 'em and try this, too
+ # $X = ($B/$A)*$A + $B % $A;
+ ($ADB,$AMB) = $B->copy()->bdiv($A);
+ ok ($B,$ADB*$A+2*$AMB-$AMB);
+ }
+
diff --git a/lib/Math/BigInt/t/sub_mbf.t b/lib/Math/BigInt/t/sub_mbf.t
index 3df9ce47f5..69a1ab9158 100755
--- a/lib/Math/BigInt/t/sub_mbf.t
+++ b/lib/Math/BigInt/t/sub_mbf.t
@@ -26,7 +26,7 @@ BEGIN
}
print "# INC = @INC\n";
- plan tests => 1592
+ plan tests => 1601
+ 6; # + our own tests
}
diff --git a/lib/Math/BigInt/t/sub_mbi.t b/lib/Math/BigInt/t/sub_mbi.t
index c492592099..95a0dae1dc 100755
--- a/lib/Math/BigInt/t/sub_mbi.t
+++ b/lib/Math/BigInt/t/sub_mbi.t
@@ -26,7 +26,7 @@ BEGIN
}
print "# INC = @INC\n";
- plan tests => 2147
+ plan tests => 2237
+ 5; # +4 own tests
}
diff --git a/lib/Math/BigInt/t/upgrade.inc b/lib/Math/BigInt/t/upgrade.inc
index 26b3a65e09..bf35261b80 100644
--- a/lib/Math/BigInt/t/upgrade.inc
+++ b/lib/Math/BigInt/t/upgrade.inc
@@ -725,9 +725,9 @@ baddNaN:+inf:NaN
-123456789:987654321:864197532
-123456789:-987654321:-1111111110
+123456789:-987654321:-864197532
-#2:2.5:4.5^
-#-123:-1.5:-124.5^
-#-1.2:1:-0.2^
+2:2.5:4.5^
+-123:-1.5:-124.5^
+-1.2:1:-0.2^
&bsub
abc:abc:NaN
abc:+0:NaN
diff --git a/lib/Math/BigInt/t/upgrade.t b/lib/Math/BigInt/t/upgrade.t
index 534c99bf12..5c8cf5fa66 100644
--- a/lib/Math/BigInt/t/upgrade.t
+++ b/lib/Math/BigInt/t/upgrade.t
@@ -10,7 +10,7 @@ BEGIN
my $location = $0; $location =~ s/upgrade.t//;
unshift @INC, $location; # to locate the testing files
chdir 't' if -d 't';
- plan tests => 2056
+ plan tests => 2068
+ 2; # our own tests
}
diff --git a/lib/Math/BigInt/t/use_lib1.t b/lib/Math/BigInt/t/use_lib1.t
new file mode 100644
index 0000000000..d737081a57
--- /dev/null
+++ b/lib/Math/BigInt/t/use_lib1.t
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+# see if using Math::BigInt and Math::BigFloat works together nicely.
+# all use_lib*.t should be equivalent
+
+use strict;
+use Test;
+
+BEGIN
+ {
+ $| = 1;
+ chdir 't' if -d 't';
+ unshift @INC, '../lib'; # for running manually
+ unshift @INC, 'lib';
+ print "# INC = @INC\n";
+ plan tests => 2;
+ }
+
+use Math::BigFloat lib => 'BareCalc';
+
+ok (Math::BigInt->config()->{lib},'Math::BigInt::BareCalc');
+
+ok (Math::BigFloat->new(123)->badd(123),246);
+
diff --git a/lib/Math/BigInt/t/use_lib2.t b/lib/Math/BigInt/t/use_lib2.t
new file mode 100644
index 0000000000..6dd744f298
--- /dev/null
+++ b/lib/Math/BigInt/t/use_lib2.t
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+# see if using Math::BigInt and Math::BigFloat works together nicely.
+# all use_lib*.t should be equivalent
+
+use strict;
+use Test;
+
+BEGIN
+ {
+ $| = 1;
+ chdir 't' if -d 't';
+ unshift @INC, '../lib'; # for running manually
+ unshift @INC, 'lib';
+ plan tests => 2;
+ }
+
+use Math::BigInt;
+use Math::BigFloat lib => 'BareCalc';
+
+ok (Math::BigInt->config()->{lib},'Math::BigInt::BareCalc');
+
+ok (Math::BigFloat->new(123)->badd(123),246);
+
diff --git a/lib/Math/BigInt/t/use_lib3.t b/lib/Math/BigInt/t/use_lib3.t
new file mode 100644
index 0000000000..3b43544660
--- /dev/null
+++ b/lib/Math/BigInt/t/use_lib3.t
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+# see if using Math::BigInt and Math::BigFloat works together nicely.
+# all use_lib*.t should be equivalent
+
+use strict;
+use Test;
+
+BEGIN
+ {
+ $| = 1;
+ chdir 't' if -d 't';
+ unshift @INC, '../lib'; # for running manually
+ unshift @INC, 'lib';
+ plan tests => 2;
+ }
+
+use Math::BigInt lib => 'BareCalc';
+use Math::BigFloat;
+
+ok (Math::BigInt->config()->{lib},'Math::BigInt::BareCalc');
+
+ok (Math::BigFloat->new(123)->badd(123),246);
+
diff --git a/lib/Math/BigInt/t/use_lib4.t b/lib/Math/BigInt/t/use_lib4.t
new file mode 100644
index 0000000000..079ba6d05f
--- /dev/null
+++ b/lib/Math/BigInt/t/use_lib4.t
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+# see if using Math::BigInt and Math::BigFloat works together nicely.
+# all use_lib*.t should be equivalent, except this, since the later overrides
+# the former lib statement
+
+use strict;
+use Test;
+
+BEGIN
+ {
+ $| = 1;
+ chdir 't' if -d 't';
+ unshift @INC, '../lib'; # for running manually
+ unshift @INC, 'lib';
+ plan tests => 2;
+ }
+
+use Math::BigInt lib => 'BareCalc';
+use Math::BigFloat lib => 'Calc';
+
+ok (Math::BigInt->config()->{lib},'Math::BigInt::Calc');
+
+ok (Math::BigFloat->new(123)->badd(123),246);
+