From: Tels Date: Sun, 3 Apr 2005 10:43:10 +0000 (+0200) Subject: [Patch] Math::BigInt v1.76, Math::BigRat v0.15, bignum v0.17 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=233f7bc03a8f0557d08657ec772040b570b403cd;p=p5sagit%2Fp5-mst-13.2.git [Patch] Math::BigInt v1.76, Math::BigRat v0.15, bignum v0.17 Message-Id: <200504031043.12273@bloodgate.com> p4raw-id: //depot/perl@24155 --- diff --git a/lib/Math/BigFloat.pm b/lib/Math/BigFloat.pm index 8143175..2300ae4 100644 --- a/lib/Math/BigFloat.pm +++ b/lib/Math/BigFloat.pm @@ -12,7 +12,7 @@ package Math::BigFloat; # _a : accuracy # _p : precision -$VERSION = '1.49'; +$VERSION = '1.50'; require 5.005; require Exporter; @@ -47,7 +47,7 @@ $upgrade = undef; $downgrade = undef; # the package we are using for our private parts, defaults to: # Math::BigInt->config()->{lib} -my $MBI = 'Math::BigInt::Calc'; +my $MBI = 'Math::BigInt::FastCalc'; # are NaNs ok? (otherwise it dies when encountering an NaN) set w/ config() $_trap_nan = 0; @@ -135,16 +135,12 @@ sub new # else: got a string # handle '+inf', '-inf' first - if ($wanted =~ /^[+-]?inf$/) + if ($wanted =~ /^[+-]?inf\z/) { return $downgrade->new($wanted) if $downgrade; - $self->{_e} = $MBI->_zero(); - $self->{_es} = '+'; - $self->{_m} = $MBI->_zero(); - $self->{sign} = $wanted; - $self->{sign} = '+inf' if $self->{sign} eq 'inf'; - return $self->bnorm(); + $self->{sign} = $wanted; # set a default sign for bstr() + return $self->binf($wanted); } # shortcut for simple forms like '12' that neither have trailing nor leading @@ -1345,11 +1341,14 @@ sub bdiv my $xsign = $x->{sign}; $y->{sign} =~ tr/+-/-+/; - my $y_not_one = !$y->is_one(); # cache this result + + # check that $y is not 1 nor -1 and cache the result: + my $y_not_one = !($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m})); + if ($xsign ne $x->{sign}) { # special case of $x /= $x results in 1 - $x->bone(); + $x->bone(); # "fixes" also sign of $y, since $x is $y } else { @@ -1443,7 +1442,10 @@ sub bmod return $x->bnan() if $x->is_zero(); return $x; } - return $x->bzero() if $y->is_one() || $x->is_zero(); + + return $x->bzero() if $x->is_zero() || + # check that $y == -1 or +1: + ($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m})); my $cmp = $x->bacmp($y); # equal or $x < $y? return $x->bzero($a,$p) if $cmp == 0; # $x == $y => result 0 @@ -2716,28 +2718,27 @@ This might change in the future, so do not depend on it. See also: L. -Math::BigFloat supports both precision and accuracy. For a full documentation, -examples and tips on these topics please see the large section in -L. +Math::BigFloat supports both precision (rounding to a certain place before or +after the dot) and accuracy (rounding to a certain number of digits). For a +full documentation, examples and tips on these topics please see the large +section about rounding in L. -Since things like sqrt(2) or 1/3 must presented with a limited precision lest -a operation consumes all resources, each operation produces no more than -the requested number of digits. +Since things like C 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. -Please refer to BigInt's documentation for the precedence rules of which -accuracy/precision setting will be used. - -If there is no gloabl precision set, B the operation inquestion was not -called with a requested precision or accuracy, B the input $x has no -accuracy or precision set, then a fallback parameter will be used. For -historical reasons, it is called C and can be accessed via: +If there is no gloabl precision or accuracy set, B the operation in +question was not called with a requested precision or accuracy, B the +input $x has no accuracy or precision set, then a fallback parameter will +be used. For historical reasons, it is called C and can be accessed +via: $d = Math::BigFloat->div_scale(); # query Math::BigFloat->div_scale($n); # set to $n digits -The default value is 40 digits. +The default value for C is 40. -In case the result of one operation has more precision than specified, +In case the result of one operation has more digits than specified, it is rounded. The rounding mode taken is either the default mode, or the one supplied to the operation after the I: @@ -2751,8 +2752,8 @@ supplied to the operation after the I: Note that C<< Math::BigFloat->accuracy() >> and C<< Math::BigFloat->precision() >> set the global variables, and thus B newly created number will be subject -to the global rounding. This means that in the examples above, the C<3> -as argument to C will also get an accuracy of B<5>. +to the global rounding B. This means that in the examples above, the +C<3> as argument to C will also get an accuracy of B<5>. It is less confusing to either calculate the result fully, and afterwards round it explicitely, or use the additional parameters to the math @@ -2821,9 +2822,48 @@ C: $x = Math::BigFloat->new(2.5); $y = $x->as_number('odd'); # $y = 3 -=head1 EXAMPLES - - # not ready yet +=head1 METHODS + +=head2 accuracy + + $x->accuracy(5); # local for $x + CLASS->accuracy(5); # global for all members of CLASS + # Note: This also applies to new()! + + $A = $x->accuracy(); # read out accuracy that affects $x + $A = CLASS->accuracy(); # read out global accuracy + +Set or get the global or local accuracy, aka how many significant digits the +results have. If you set a global accuracy, then this also applies to new()! + +Warning! The accuracy I, e.g. once you created a number under the +influence of C<< CLASS->accuracy($A) >>, all results from math operations with +that number will also be rounded. + +In most cases, you should probably round the results explicitely using one of +L, L or L or by passing the desired accuracy +to the math operation as additional parameter: + + my $x = Math::BigInt->new(30000); + my $y = Math::BigInt->new(7); + print scalar $x->copy()->bdiv($y, 2); # print 4300 + print scalar $x->copy()->bdiv($y)->bround(2); # print 4300 + +=head2 precision() + + $x->precision(-2); # local for $x, round at the second digit right of the dot + $x->precision(2); # ditto, round at the second digit left of the dot + + CLASS->precision(5); # Global for all members of CLASS + # This also applies to new()! + CLASS->precision(-5); # ditto + + $P = CLASS->precision(); # read out global precision + $P = $x->precision(); # read out precision that affects $x + +Note: You probably want to use L instead. With L you +set the number of digits each result should have, with L you +set the place where to round! =head1 Autocreating constants @@ -3031,6 +3071,49 @@ C etc. The first will modify $x, the second one won't: print $x->bpow($i),"\n"; # ditto print $x ** $i,"\n"; # leave $x alone +=item precision() vs. accuracy() + +A common pitfall is to use L when you want to round a result to +a certain number of digits: + + use Math::BigFloat; + + Math::BigFloat->precision(4); # does not do what you think it does + my $x = Math::BigFloat->new(12345); # rounds $x to "12000"! + print "$x\n"; # print "12000" + my $y = Math::BigFloat->new(3); # rounds $y to "0"! + print "$y\n"; # print "0" + $z = $x / $y; # 12000 / 0 => NaN! + print "$z\n"; + print $z->precision(),"\n"; # 4 + +Replacing L with L is probably not what you want, either: + + use Math::BigFloat; + + Math::BigFloat->accuracy(4); # enables global rounding: + my $x = Math::BigFloat->new(123456); # rounded immidiately to "12350" + print "$x\n"; # print "123500" + my $y = Math::BigFloat->new(3); # rounded to "3 + print "$y\n"; # print "3" + print $z = $x->copy()->bdiv($y),"\n"; # 41170 + print $z->accuracy(),"\n"; # 4 + +What you want to use instead is: + + use Math::BigFloat; + + my $x = Math::BigFloat->new(123456); # no rounding + print "$x\n"; # print "123456" + my $y = Math::BigFloat->new(3); # no rounding + print "$y\n"; # print "3" + print $z = $x->copy()->bdiv($y,4),"\n"; # 41150 + print $z->accuracy(),"\n"; # undef + +In addition to computing what you expected, the last example also does B +"taint" the result with an accuracy or precision setting, which would +influence any further operation. + =back =head1 SEE ALSO diff --git a/lib/Math/BigInt.pm b/lib/Math/BigInt.pm index 1d31534..dc428e7 100644 --- a/lib/Math/BigInt.pm +++ b/lib/Math/BigInt.pm @@ -18,10 +18,10 @@ package Math::BigInt; my $class = "Math::BigInt"; require 5.005; -$VERSION = '1.75'; +$VERSION = '1.76'; -@ISA = qw( Exporter ); -@EXPORT_OK = qw( objectify bgcd blcm); +@ISA = qw(Exporter); +@EXPORT_OK = qw(objectify bgcd blcm); # _trap_inf and _trap_nan are internal and should never be accessed from the # outside @@ -162,8 +162,8 @@ $_trap_nan = 0; # are NaNs ok? set w/ config() $_trap_inf = 0; # are infs ok? set w/ config() my $nan = 'NaN'; # constants for easier life -my $CALC = 'Math::BigInt::Calc'; # module to do the low level math - # default is Calc.pm +my $CALC = 'Math::BigInt::FastCalc'; # module to do the low level math + # default is FastCalc.pm my $IMPORT = 0; # was import() called yet? # used to make require work my %WARN; # warn only once for low-level libs @@ -528,11 +528,10 @@ sub new } # handle '+inf', '-inf' first - if ($wanted =~ /^[+-]?inf$/) + if ($wanted =~ /^[+-]?inf\z/) { - $self->{value} = $CALC->_zero(); - $self->{sign} = $wanted; $self->{sign} = '+inf' if $self->{sign} eq 'inf'; - return $self; + $self->{sign} = $wanted; # set a default sign for bstr() + return $self->binf($wanted); } # split str in m mantissa, e exponent, i integer, f fraction, v value, s sign my ($mis,$miv,$mfv,$es,$ev) = _split($wanted); @@ -663,7 +662,7 @@ sub binf if (${"${class}::_trap_inf"}) { require Carp; - Carp::croak ("Tried to set $self to +-inf in $class\::binfn()"); + Carp::croak ("Tried to set $self to +-inf in $class\::binf()"); } $self->import() if $IMPORT == 0; # make require work return if $self->modify('binf'); @@ -2414,7 +2413,7 @@ sub import { $_ =~ tr/a-zA-Z0-9://cd; # limit to sane characters } - push @c,'Calc'; # if all fail, try this + push @c, 'FastCalc', 'Calc'; # if all fail, try these $CALC = ''; # signal error foreach my $lib (@c) { @@ -2640,9 +2639,11 @@ sub modify () { 0; } 1; __END__ +=pod + =head1 NAME -Math::BigInt - Arbitrary size integer math package +Math::BigInt - Arbitrary size integer/float math package =head1 SYNOPSIS @@ -2890,11 +2891,26 @@ Example: $x->accuracy(5); # local for $x CLASS->accuracy(5); # global for all members of CLASS - $A = $x->accuracy(); # read out - $A = CLASS->accuracy(); # read out + # Note: This also applies to new()! + + $A = $x->accuracy(); # read out accuracy that affects $x + $A = CLASS->accuracy(); # read out global accuracy Set or get the global or local accuracy, aka how many significant digits the -results have. +results have. If you set a global accuracy, then this also applies to new()! + +Warning! The accuracy I, e.g. once you created a number under the +influence of C<< CLASS->accuracy($A) >>, all results from math operations with +that number will also be rounded. + +In most cases, you should probably round the results explicitely using one of +L, L or L or by passing the desired accuracy +to the math operation as additional parameter: + + my $x = Math::BigInt->new(30000); + my $y = Math::BigInt->new(7); + print scalar $x->copy()->bdiv($y, 2); # print 4300 + print scalar $x->copy()->bdiv($y)->bround(2); # print 4300 Please see the section about L for further details. @@ -2909,7 +2925,7 @@ 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 + $x = Math::BigInt->new(123456); # $x will be automatically rounded! print "$x $y\n"; # '123500 1234567' print $x->accuracy(),"\n"; # will be 4 print $y->accuracy(),"\n"; # also 4, since global is 4 @@ -2924,35 +2940,46 @@ 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 + $x->precision(-2); # local for $x, round at the second digit right of the dot + $x->precision(2); # ditto, round at the second digit left of the dot + + CLASS->precision(5); # Global for all members of CLASS + # This also applies to new()! + CLASS->precision(-5); # ditto + + $P = CLASS->precision(); # read out global precision + $P = $x->precision(); # read out precision that affects $x + +Note: You probably want to use L instead. With L you +set the number of digits each result should have, with L you +set the place where to round! -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. +C sets or gets the global or local precision, aka at which digit +before or after the dot to round all results. A set global precision also +applies to all newly created numbers! + +In Math::BigInt, passing a negative number precision has no effect since no +numbers have digits after the dot. In L, it will round all +results to P digits after the dot. Please see the section about L for further details. -Value must be greater than zero. Pass an undef value to disable it: +Pass an undef value to disable it: $x->precision(undef); Math::BigInt->precision(undef); Returns the current precision. For C<$x->precision()> it will return either the local precision of $x, or if not defined, the global. This means the return -value represents the accuracy that will be in effect for $x: +value represents the prevision that will be in effect for $x: $y = Math::BigInt->new(1234567); # unrounded print Math::BigInt->precision(4),"\n"; # set 4, print 4 $x = Math::BigInt->new(123456); # will be automatically rounded + print $x; # print "120000"! -Note: Works also for subclasses like Math::BigFloat. Each class has it's own -globals separated from Math::BigInt, but it is possible to subclass +Note: Works also for subclasses like L. Each class has its +own globals separated from Math::BigInt, but it is possible to subclass Math::BigInt and make the globals of the subclass aliases to the ones from Math::BigInt. diff --git a/lib/Math/BigInt/Calc.pm b/lib/Math/BigInt/Calc.pm index eb5ba98..56b6aab 100644 --- a/lib/Math/BigInt/Calc.pm +++ b/lib/Math/BigInt/Calc.pm @@ -6,7 +6,7 @@ use strict; use vars qw/$VERSION/; -$VERSION = '0.45'; +$VERSION = '0.46'; # Package to store unsigned big integers in decimal and do math with them @@ -36,7 +36,7 @@ $VERSION = '0.45'; sub api_version () { 1; } # constants for easier life -my ($MBASE,$BASE,$RBASE,$BASE_LEN,$MAX_VAL,$BASE_LEN_SMALL); +my ($BASE,$BASE_LEN,$MBASE,$RBASE,$MAX_VAL,$BASE_LEN_SMALL); my ($AND_BITS,$XOR_BITS,$OR_BITS); my ($AND_MASK,$XOR_MASK,$OR_MASK); @@ -94,7 +94,7 @@ sub _base_len } } return $BASE_LEN unless wantarray; - return ($BASE_LEN, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN_SMALL, $MAX_VAL); + return ($BASE_LEN, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN_SMALL, $MAX_VAL, $BASE); } sub _new diff --git a/lib/Math/BigInt/t/_e_math.t b/lib/Math/BigInt/t/_e_math.t index 3db3318..b3eb644 100644 --- a/lib/Math/BigInt/t/_e_math.t +++ b/lib/Math/BigInt/t/_e_math.t @@ -31,7 +31,7 @@ BEGIN plan tests => 26; } -use Math::BigFloat; +use Math::BigFloat lib => 'Calc'; ############################################################################# # add diff --git a/lib/Math/BigInt/t/bare_mbf.t b/lib/Math/BigInt/t/bare_mbf.t index 9a12572..29a73a0 100644 --- a/lib/Math/BigInt/t/bare_mbf.t +++ b/lib/Math/BigInt/t/bare_mbf.t @@ -27,7 +27,7 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 1992; + plan tests => 2012; } use Math::BigFloat lib => 'BareCalc'; diff --git a/lib/Math/BigInt/t/bigfltpm.inc b/lib/Math/BigInt/t/bigfltpm.inc index 5f27a8b..4099521 100644 --- a/lib/Math/BigInt/t/bigfltpm.inc +++ b/lib/Math/BigInt/t/bigfltpm.inc @@ -1221,6 +1221,11 @@ NaNmul:-inf:NaN 0:1:0,0 9:4:2.25,1 9:5:1.8,4 +# bug in v1.74 with bdiv in list context, when $y is 1 or -1 +2.1:-1:-2.1,0 +2.1:1:2.1,0 +-2.1:-1:2.1,0 +-2.1:1:-2.1,0 &fdiv $div_scale = 40; $round_mode = 'even' abc:abc:NaN @@ -1382,6 +1387,15 @@ abc:1:abc:NaN 1230:2.5:0 123.4:2.5:0.9 123e1:25:5 +# 1 or -1 always gives remainder zero (bug up to v1.74) +-2.1:1:0 +2.1:1:0 +-2.1:-1:0 +2.1:-1:0 +-3:1:0 +3:1:0 +-3:-1:0 +3:-1:0 &ffac Nanfac:NaN -1:NaN diff --git a/lib/Math/BigInt/t/bigfltpm.t b/lib/Math/BigInt/t/bigfltpm.t index 5cc9ddb..c444028 100755 --- a/lib/Math/BigInt/t/bigfltpm.t +++ b/lib/Math/BigInt/t/bigfltpm.t @@ -26,11 +26,11 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 1992 + plan tests => 2012 + 2; # own tests } -use Math::BigInt; +use Math::BigInt lib => 'Calc'; use Math::BigFloat; use vars qw ($class $try $x $y $f @args $ans $ans1 $ans1_str $setup $CL); diff --git a/lib/Math/BigInt/t/bigintpm.t b/lib/Math/BigInt/t/bigintpm.t index 9923256..431ab02 100755 --- a/lib/Math/BigInt/t/bigintpm.t +++ b/lib/Math/BigInt/t/bigintpm.t @@ -13,7 +13,7 @@ BEGIN plan tests => 3014; } -use Math::BigInt; +use Math::BigInt lib => 'Calc'; use vars qw ($scale $class $try $x $y $f @args $ans $ans1 $ans1_str $setup $CL); $class = "Math::BigInt"; diff --git a/lib/Math/BigInt/t/calling.t b/lib/Math/BigInt/t/calling.t index 71c6b48..7376bad 100644 --- a/lib/Math/BigInt/t/calling.t +++ b/lib/Math/BigInt/t/calling.t @@ -55,11 +55,11 @@ use overload; package main; -use Math::BigInt; +use Math::BigInt lib => 'Calc'; use Math::BigFloat; my ($x,$y,$z,$u); -my $version = '1.61'; # adjust manually to match latest release +my $version = '1.76'; # adjust manually to match latest release ############################################################################### # check whether op's accept normal strings, even when inherited by subclasses @@ -106,7 +106,7 @@ $class = 'Math::BigInt'; $try = "use $class ($version,'lib','foo, bar , ');"; $try .= "$class\->config()->{lib};"; $ans = eval $try; -ok ( $ans, "Math::BigInt::Calc"); +ok ( $ans =~ /^Math::BigInt::(Fast)?Calc\z/, 1); # test whether constant works or not, also test for qw($version) # bgcd() is present in subclass, too @@ -125,17 +125,6 @@ $ans = eval $try; ok ( $ans, "1024"); # all done -############################################################################### -# Perl 5.005 does not like ok ($x,undef) - -sub ok_undef - { - my $x = shift; - - ok (1,1) and return if !defined $x; - ok ($x,'undef'); - } - __END__ &is_zero 1:0 diff --git a/lib/Math/BigInt/t/config.t b/lib/Math/BigInt/t/config.t index da75344..68509c0 100644 --- a/lib/Math/BigInt/t/config.t +++ b/lib/Math/BigInt/t/config.t @@ -13,7 +13,7 @@ BEGIN # test whether Math::BigInt->config() and Math::BigFloat->config() works -use Math::BigInt; +use Math::BigInt lib => 'Calc'; use Math::BigFloat; my $mbi = 'Math::BigInt'; my $mbf = 'Math::BigFloat'; @@ -105,16 +105,16 @@ foreach my $key (keys %$test) ############################################################################## # test setting illegal keys (should croak) -my $never_reached = 0; +$@ = ""; my $never_reached = 0; eval ("$mbi\->config( 'some_garbage' => 1 ); $never_reached = 1;"); ok ($never_reached,0); -$never_reached = 0; +$@ = ""; $never_reached = 0; eval ("$mbf\->config( 'some_garbage' => 1 ); $never_reached = 1;"); ok ($never_reached,0); # this does not work. Why? -#ok (@!, "Illegal keys 'some_garbage' passed to Math::BigInt->config() at ./config.t line 104"); +#ok ($@ eq "Illegal keys 'some_garbage' passed to Math::BigInt->config() at ./config.t line 104", 1); # all tests done diff --git a/lib/Math/BigInt/t/req_mbf0.t b/lib/Math/BigInt/t/req_mbf0.t index af312f1..90cd57c 100644 --- a/lib/Math/BigInt/t/req_mbf0.t +++ b/lib/Math/BigInt/t/req_mbf0.t @@ -3,7 +3,7 @@ # check that simple requiring BigFloat and then bzero() works use strict; -use Test; +use Test::More; BEGIN { @@ -31,7 +31,9 @@ BEGIN plan tests => 1; } -require Math::BigFloat; my $x = Math::BigFloat->bzero(); ok ($x,0); +require Math::BigFloat; +my $x = Math::BigFloat->bzero(); $x++; +is ($x,1, '$x is 1'); # all tests done diff --git a/lib/Math/BigInt/t/req_mbfw.t b/lib/Math/BigInt/t/req_mbfw.t index 025722d..10afc7a 100644 --- a/lib/Math/BigInt/t/req_mbfw.t +++ b/lib/Math/BigInt/t/req_mbfw.t @@ -3,7 +3,7 @@ # check that requiring BigFloat and then calling import() works use strict; -use Test; +use Test::More; BEGIN { @@ -32,15 +32,17 @@ BEGIN } # normal require that calls import automatically (we thus have MBI afterwards) -require Math::BigFloat; my $x = Math::BigFloat->new(1); ++$x; ok ($x,2); +require Math::BigFloat; +my $x = Math::BigFloat->new(1); ++$x; +is ($x,2, '$x is 2'); -ok (Math::BigFloat->config()->{with}, 'Math::BigInt::Calc' ); +like (Math::BigFloat->config()->{with}, qr/^Math::BigInt::(Fast)?Calc\z/, 'with ignored' ); # now override Math::BigFloat->import ( with => 'Math::BigInt::Subclass' ); -# thw with argument is ignored -ok (Math::BigFloat->config()->{with}, 'Math::BigInt::Calc' ); +# the "with" argument is ignored +like (Math::BigFloat->config()->{with}, qr/^Math::BigInt::(Fast)?Calc\z/, 'with ignored' ); # all tests done diff --git a/lib/Math/BigInt/t/sub_mbf.t b/lib/Math/BigInt/t/sub_mbf.t index 73d7fc0..3033ee2 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 => 1992 + plan tests => 2012 + 6; # + our own tests } @@ -34,7 +34,7 @@ use Math::BigFloat::Subclass; use vars qw ($class $try $x $y $f @args $ans $ans1 $ans1_str $setup $CL); $class = "Math::BigFloat::Subclass"; -$CL = "Math::BigInt::Calc"; +$CL = Math::BigFloat->config()->{lib}; # "Math::BigInt::Calc"; or FastCalc require 'bigfltpm.inc'; # perform same tests as bigfltpm diff --git a/lib/Math/BigInt/t/trap.t b/lib/Math/BigInt/t/trap.t index af45409..94a7da4 100644 --- a/lib/Math/BigInt/t/trap.t +++ b/lib/Math/BigInt/t/trap.t @@ -3,14 +3,14 @@ # test that config ( trap_nan => 1, trap_inf => 1) really works/dies use strict; -use Test; +use Test::More; BEGIN { $| = 1; chdir 't' if -d 't'; unshift @INC, '../lib'; # for running manually - plan tests => 35; + plan tests => 43; } use Math::BigInt; @@ -22,42 +22,54 @@ my ($cfg,$x); foreach my $class ($mbi, $mbf) { # can do and defaults are okay? - ok ($class->can('config')); - ok ($class->config()->{trap_nan}, 0); - ok ($class->config()->{trap_inf}, 0); + ok ($class->can('config'), 'can config()'); + is ($class->config()->{trap_nan}, 0, 'trap_nan defaults to 0'); + is ($class->config()->{trap_inf}, 0, 'trap_inf defaults to 0'); # can set? - $cfg = $class->config( trap_nan => 1 ); ok ($cfg->{trap_nan},1); + $cfg = $class->config( trap_nan => 1 ); + is ($cfg->{trap_nan},1, 'trap_nan now true'); # also test that new() still works normally eval ("\$x = \$class->new('42'); \$x->bnan();"); - ok ($@ =~/^Tried to set/, 1); - ok ($x,42); # after new() never modified + like ($@, qr/^Tried to set/, 'died'); + is ($x,42,'$x after new() never modified'); # can reset? - $cfg = $class->config( trap_nan => 0 ); ok ($cfg->{trap_nan},0); + $cfg = $class->config( trap_nan => 0 ); + is ($cfg->{trap_nan}, 0, 'trap_nan disabled'); # can set? - $cfg = $class->config( trap_inf => 1 ); ok ($cfg->{trap_inf},1); + $cfg = $class->config( trap_inf => 1 ); + is ($cfg->{trap_inf}, 1, 'trap_inf enabled'); + eval ("\$x = \$class->new('4711'); \$x->binf();"); - ok ($@ =~/^Tried to set/, 1); - ok ($x,4711); # after new() never modified + like ($@, qr/^Tried to set/, 'died'); + is ($x,4711,'$x after new() never modified'); + + eval ("\$x = \$class->new('inf');"); + like ($@, qr/^Tried to set/, 'died'); + is ($x,4711,'$x after new() never modified'); + + eval ("\$x = \$class->new('-inf');"); + like ($@, qr/^Tried to set/, 'died'); + is ($x,4711,'$x after new() never modified'); # +$x/0 => +inf eval ("\$x = \$class->new('4711'); \$x->bdiv(0);"); - ok ($@ =~/^Tried to set/, 1); - ok ($x,4711); # after new() never modified + like ($@, qr/^Tried to set/, 'died'); + is ($x,4711,'$x after new() never modified'); # -$x/0 => -inf eval ("\$x = \$class->new('-0815'); \$x->bdiv(0);"); - ok ($@ =~/^Tried to set/, 1); - ok ($x,-815); # after new() never modified + like ($@, qr/^Tried to set/, 'died'); + is ($x,'-815', '$x after new not modified'); $cfg = $class->config( trap_nan => 1 ); # 0/0 => NaN eval ("\$x = \$class->new('0'); \$x->bdiv(0);"); - ok ($@ =~/^Tried to set/, 1); - ok ($x,0); # after new() never modified + like ($@, qr/^Tried to set/, 'died'); + is ($x,'0', '$x after new not modified'); } ############################################################################## @@ -65,17 +77,16 @@ foreach my $class ($mbi, $mbf) $x = Math::BigInt->new(2); eval ("\$x = \$mbi->new('0.1');"); -ok ($x,2); # never modified since it dies +is ($x,2,'never modified since it dies'); eval ("\$x = \$mbi->new('0a.1');"); -ok ($x,2); # never modified since it dies - +is ($x,2,'never modified since it dies'); ############################################################################## # BigFloat $x = Math::BigFloat->new(2); eval ("\$x = \$mbf->new('0.1a');"); -ok ($x,2); # never modified since it dies +is ($x,2,'never modified since it dies'); # all tests done diff --git a/lib/Math/BigInt/t/with_sub.t b/lib/Math/BigInt/t/with_sub.t index 0ed85a4..07320a9 100644 --- a/lib/Math/BigInt/t/with_sub.t +++ b/lib/Math/BigInt/t/with_sub.t @@ -28,11 +28,11 @@ BEGIN } print "# INC = @INC\n"; - plan tests => 1992 + plan tests => 2012 + 1; } -use Math::BigFloat with => 'Math::BigInt::Subclass'; +use Math::BigFloat with => 'Math::BigInt::Subclass', lib => 'Calc'; use vars qw ($class $try $x $y $f @args $ans $ans1 $ans1_str $setup $CL); $class = "Math::BigFloat"; diff --git a/lib/Math/BigRat.pm b/lib/Math/BigRat.pm index 523088a..6243dd4 100644 --- a/lib/Math/BigRat.pm +++ b/lib/Math/BigRat.pm @@ -16,14 +16,13 @@ package Math::BigRat; require 5.005_03; use strict; -require Exporter; use Math::BigFloat; use vars qw($VERSION @ISA $upgrade $downgrade $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf); -@ISA = qw(Exporter Math::BigFloat); +@ISA = qw(Math::BigFloat); -$VERSION = '0.14'; +$VERSION = '0.15'; use overload; # inherit overload from Math::BigFloat @@ -61,7 +60,6 @@ my $MBI = 'Math::BigInt::Calc'; my $nan = 'NaN'; my $class = 'Math::BigRat'; -my $IMPORT = 0; sub isa { @@ -201,6 +199,7 @@ sub new my $nf = Math::BigFloat->new($n,undef,undef); $self->{sign} = '+'; return $self->bnan() if $nf->is_nan(); + $self->{_n} = $MBI->_copy( $nf->{_m} ); # get mantissa # now correct $self->{_n} due to $n @@ -245,7 +244,7 @@ sub new { $d = Math::BigInt->new($d,undef,undef) unless ref $d; $n = Math::BigInt->new($n,undef,undef) unless ref $n; - + if ($n->{sign} =~ /^[+-]$/ && $d->{sign} =~ /^[+-]$/) { # both parts are ok as integers (wierd things like ' 1e0' @@ -448,6 +447,10 @@ sub _bnan { require Carp; my $class = ref($self); + # "$self" below will stringify the object, this blows up if $self is a + # partial object (happens under trap_nan), so fix it beforehand + $self->{_d} = $MBI->_zero() unless defined $self->{_d}; + $self->{_n} = $MBI->_zero() unless defined $self->{_n}; Carp::croak ("Tried to set $self to NaN in $class\::_bnan()"); } $self->{_n} = $MBI->_zero(); @@ -463,6 +466,10 @@ sub _binf { require Carp; my $class = ref($self); + # "$self" below will stringify the object, this blows up if $self is a + # partial object (happens under trap_nan), so fix it beforehand + $self->{_d} = $MBI->_zero() unless defined $self->{_d}; + $self->{_n} = $MBI->_zero() unless defined $self->{_n}; Carp::croak ("Tried to set $self to inf in $class\::_binf()"); } $self->{_n} = $MBI->_zero(); @@ -512,21 +519,25 @@ sub badd # 4 3 4*3 12 # we do not compute the gcd() here, but simple do: - # 5 7 5*3 + 7*4 41 + # 5 7 5*3 + 7*4 43 # - + - = --------- = -- # 4 3 4*3 12 # and bnorm() will then take care of the rest + # 5 * 3 $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d}); + # 7 * 4 my $m = $MBI->_mul( $MBI->_copy( $y->{_n} ), $x->{_d} ); + # 5 * 3 + 7 * 4 ($x->{_n}, $x->{sign}) = _e_add( $x->{_n}, $m, $x->{sign}, $y->{sign}); + # 4 * 3 $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d}); - # normalize and round + # normalize result, and possible round $x->bnorm()->round(@r); } @@ -1305,7 +1316,6 @@ sub import my $self = shift; my $l = scalar @_; my $lib = ''; my @a; - $IMPORT++; for ( my $i = 0; $i < $l ; $i++) { @@ -1333,7 +1343,8 @@ sub import } elsif ($_[$i] eq 'with') { - $MBI = $_[$i+1] || 'Math::BigInt::Calc'; # default Math::BigInt::Calc + # this argument is no longer used + #$MBI = $_[$i+1] || 'Math::BigInt::Calc'; # default Math::BigInt::Calc $i++; } else @@ -1351,17 +1362,21 @@ sub import { $_ =~ tr/a-zA-Z0-9://cd; # limit to sane characters } - # MBI already loaded, so feed it our lib arguments - $MBI->import('lib' => $lib . join(",",@c), 'objectify'); + $lib = join(",", @c); } + my @import = ('objectify'); + push @import, lib => $lib if $lib ne ''; + + # MBI already loaded, so feed it our lib arguments + Math::BigInt->import( @import ); $MBI = Math::BigFloat->config()->{lib}; # register us with MBI to get notified of future lib changes Math::BigInt::_register_callback( $self, sub { $MBI = $_[0]; } ); - # any non :constant stuff is handled by our parent, Exporter - # even if @_ is empty, to give it a chance + # any non :constant stuff is handled by our parent, Exporter (loaded + # by Math::BigFloat, even if @_ is empty, to give it a chance $self->SUPER::import(@a); # for subclasses $self->export_to_level(1,$self,@a); # need this, too } diff --git a/lib/Math/BigRat/t/bigratpm.t b/lib/Math/BigRat/t/bigratpm.t index 510bccd..465d698 100755 --- a/lib/Math/BigRat/t/bigratpm.t +++ b/lib/Math/BigRat/t/bigratpm.t @@ -29,7 +29,7 @@ BEGIN plan tests => 686; } -use Math::BigRat; +use Math::BigRat lib => 'Calc'; use vars qw ($class $try $x $y $f @args $ans $ans1 $ans1_str $setup $CL); $class = "Math::BigRat"; diff --git a/lib/Math/BigRat/t/requirer.t b/lib/Math/BigRat/t/requirer.t index 6805658..8be2fa8 100644 --- a/lib/Math/BigRat/t/requirer.t +++ b/lib/Math/BigRat/t/requirer.t @@ -3,7 +3,7 @@ # check that simple requiring BigRat works use strict; -use Test; +use Test::More; BEGIN { @@ -35,7 +35,7 @@ my ($x); require Math::BigRat; $x = Math::BigRat->new(1); ++$x; -ok ($x||'undef',2); +is ($x, 2, '$x got successfully modified'); # all tests done diff --git a/lib/bigint.pm b/lib/bigint.pm index 695b4c4..a53891a 100644 --- a/lib/bigint.pm +++ b/lib/bigint.pm @@ -1,7 +1,7 @@ package bigint; require 5.005; -$VERSION = '0.06'; +$VERSION = '0.07'; use Exporter; @ISA = qw( Exporter ); @EXPORT_OK = qw( ); @@ -102,7 +102,7 @@ sub import my $self = shift; # some defaults - my $lib = 'Calc'; + my $lib = ''; my @import = ( ':constant' ); # drive it w/ constant my @a = @_; my $l = scalar @_; my $j = 0; @@ -162,9 +162,10 @@ sub import } require Math::BigInt if $_lite == 0; # not already loaded? $class = 'Math::BigInt'; # regardless of MBIL or not - } + } + push @import, 'lib' => $lib if $lib ne ''; # Math::BigInt::Trace or plain Math::BigInt - $class->import(@import, lib => $lib); + $class->import(@import); bigint->accuracy($a) if defined $a; bigint->precision($p) if defined $p; diff --git a/lib/bignum.pm b/lib/bignum.pm index db03d98..951bf95 100644 --- a/lib/bignum.pm +++ b/lib/bignum.pm @@ -1,7 +1,7 @@ package bignum; require 5.005; -$VERSION = '0.16'; +$VERSION = '0.17'; use Exporter; @EXPORT_OK = qw( ); @EXPORT = qw( inf NaN ); @@ -63,7 +63,7 @@ sub import my $self = shift; # some defaults - my $lib = 'Calc'; + my $lib = ''; my $upgrade = 'Math::BigFloat'; my $downgrade = 'Math::BigInt'; @@ -140,9 +140,10 @@ sub import } require Math::BigInt if $_lite == 0; # not already loaded? $class = 'Math::BigInt'; # regardless of MBIL or not - } + } + push @import, 'lib' => $lib if $lib ne ''; # Math::BigInt::Trace or plain Math::BigInt - $class->import(@import, upgrade => $upgrade, lib => $lib); + $class->import(@import, upgrade => $upgrade); if ($trace) { diff --git a/lib/bigrat.pm b/lib/bigrat.pm index b2a26d6..8085b74 100644 --- a/lib/bigrat.pm +++ b/lib/bigrat.pm @@ -1,7 +1,7 @@ package bigrat; require 5.005; -$VERSION = '0.07'; +$VERSION = '0.08'; require Exporter; @ISA = qw( Exporter ); @EXPORT_OK = qw( ); @@ -66,7 +66,7 @@ sub import # see also bignum->import() for additional comments # some defaults - my $lib = 'Calc'; my $upgrade = 'Math::BigFloat'; + my $lib = ''; my $upgrade = 'Math::BigFloat'; my @import = ( ':constant' ); # drive it w/ constant my @a = @_; my $l = scalar @_; my $j = 0; @@ -138,8 +138,9 @@ sub import require Math::BigInt if $_lite == 0; # not already loaded? $class = 'Math::BigInt'; # regardless of MBIL or not } + push @import, 'lib' => $lib if $lib ne ''; # Math::BigInt::Trace or plain Math::BigInt - $class->import(@import, upgrade => $upgrade, lib => $lib); + $class->import(@import, upgrade => $upgrade); require Math::BigFloat; Math::BigFloat->import( upgrade => 'Math::BigRat', ':constant' );