diff options
Diffstat (limited to 'lib/Math/BigInt/t/mbimbf.inc')
-rw-r--r-- | lib/Math/BigInt/t/mbimbf.inc | 967 |
1 files changed, 0 insertions, 967 deletions
diff --git a/lib/Math/BigInt/t/mbimbf.inc b/lib/Math/BigInt/t/mbimbf.inc deleted file mode 100644 index b057eee3ec..0000000000 --- a/lib/Math/BigInt/t/mbimbf.inc +++ /dev/null @@ -1,967 +0,0 @@ -# test rounding, accuracy, precicion and fallback, round_mode and mixing -# of classes - -# Make sure you always quote any bare floating-point values, lest 123.46 will -# be stringified to 123.4599999999 due to limited float prevision. - -use strict; -my ($x,$y,$z,$u,$rc); - -############################################################################### -# test defaults and set/get - -{ - no strict 'refs'; - ok_undef (${"$mbi\::accuracy"}); - ok_undef (${"$mbi\::precision"}); - ok_undef ($mbi->accuracy()); - ok_undef ($mbi->precision()); - ok (${"$mbi\::div_scale"},40); - ok (${"$mbi\::round_mode"},'even'); - ok ($mbi->round_mode(),'even'); - - ok_undef (${"$mbf\::accuracy"}); - ok_undef (${"$mbf\::precision"}); - ok_undef ($mbf->precision()); - ok_undef ($mbf->precision()); - ok (${"$mbf\::div_scale"},40); - ok (${"$mbf\::round_mode"},'even'); - ok ($mbf->round_mode(),'even'); -} - -# accessors -foreach my $class ($mbi,$mbf) - { - ok_undef ($class->accuracy()); - ok_undef ($class->precision()); - ok ($class->round_mode(),'even'); - ok ($class->div_scale(),40); - - ok ($class->div_scale(20),20); - $class->div_scale(40); ok ($class->div_scale(),40); - - ok ($class->round_mode('odd'),'odd'); - $class->round_mode('even'); ok ($class->round_mode(),'even'); - - ok ($class->accuracy(2),2); - $class->accuracy(3); ok ($class->accuracy(),3); - ok_undef ($class->accuracy(undef)); - - ok ($class->precision(2),2); - ok ($class->precision(-2),-2); - $class->precision(3); ok ($class->precision(),3); - ok_undef ($class->precision(undef)); - } - -{ - no strict 'refs'; - # accuracy - foreach (qw/5 42 -1 0/) - { - ok (${"$mbf\::accuracy"} = $_,$_); - ok (${"$mbi\::accuracy"} = $_,$_); - } - ok_undef (${"$mbf\::accuracy"} = undef); - ok_undef (${"$mbi\::accuracy"} = undef); - - # precision - foreach (qw/5 42 -1 0/) - { - ok (${"$mbf\::precision"} = $_,$_); - ok (${"$mbi\::precision"} = $_,$_); - } - ok_undef (${"$mbf\::precision"} = undef); - ok_undef (${"$mbi\::precision"} = undef); - - # fallback - foreach (qw/5 42 1/) - { - ok (${"$mbf\::div_scale"} = $_,$_); - ok (${"$mbi\::div_scale"} = $_,$_); - } - # illegal values are possible for fallback due to no accessor - - # round_mode - foreach (qw/odd even zero trunc +inf -inf/) - { - ok (${"$mbf\::round_mode"} = $_,$_); - ok (${"$mbi\::round_mode"} = $_,$_); - } - ${"$mbf\::round_mode"} = 'zero'; - ok (${"$mbf\::round_mode"},'zero'); - ok (${"$mbi\::round_mode"},'-inf'); # from above - - # reset for further tests - ${"$mbi\::accuracy"} = undef; - ${"$mbi\::precision"} = undef; - ${"$mbf\::div_scale"} = 40; -} - -# local copies -$x = $mbf->new('123.456'); -ok_undef ($x->accuracy()); -ok ($x->accuracy(5),5); -ok_undef ($x->accuracy(undef),undef); -ok_undef ($x->precision()); -ok ($x->precision(5),5); -ok_undef ($x->precision(undef),undef); - -{ - no strict 'refs'; - # see if MBF changes MBIs values - ok (${"$mbi\::accuracy"} = 42,42); - ok (${"$mbf\::accuracy"} = 64,64); - ok (${"$mbi\::accuracy"},42); # should be still 42 - ok (${"$mbf\::accuracy"},64); # should be now 64 -} - -############################################################################### -# see if creating a number under set A or P will round it - -{ - no strict 'refs'; - ${"$mbi\::accuracy"} = 4; - ${"$mbi\::precision"} = undef; - - ok ($mbi->new(123456),123500); # with A - ${"$mbi\::accuracy"} = undef; - ${"$mbi\::precision"} = 3; - ok ($mbi->new(123456),123000); # with P - - ${"$mbf\::accuracy"} = 4; - ${"$mbf\::precision"} = undef; - ${"$mbi\::precision"} = undef; - - ok ($mbf->new('123.456'),'123.5'); # with A - ${"$mbf\::accuracy"} = undef; - ${"$mbf\::precision"} = -1; - ok ($mbf->new('123.456'),'123.5'); # with P from MBF, not MBI! - - ${"$mbf\::precision"} = undef; # reset -} - -############################################################################### -# see if MBI leaves MBF's private parts alone - -{ - no strict 'refs'; - ${"$mbi\::precision"} = undef; ${"$mbf\::precision"} = undef; - ${"$mbi\::accuracy"} = 4; ${"$mbf\::accuracy"} = undef; - ok ($mbf->new('123.456'),'123.456'); - ${"$mbi\::accuracy"} = undef; # reset -} - -############################################################################### -# see if setting accuracy/precision actually rounds the number - -$x = $mbf->new('123.456'); $x->accuracy(4); ok ($x,'123.5'); -$x = $mbf->new('123.456'); $x->precision(-2); ok ($x,'123.46'); - -$x = $mbi->new(123456); $x->accuracy(4); ok ($x,123500); -$x = $mbi->new(123456); $x->precision(2); ok ($x,123500); - -############################################################################### -# test actual rounding via round() - -$x = $mbf->new('123.456'); -ok ($x->copy()->round(5),'123.46'); -ok ($x->copy()->round(4),'123.5'); -ok ($x->copy()->round(5,2),'NaN'); -ok ($x->copy()->round(undef,-2),'123.46'); -ok ($x->copy()->round(undef,2),120); - -$x = $mbi->new('123'); -ok ($x->round(5,2),'NaN'); - -$x = $mbf->new('123.45000'); -ok ($x->copy()->round(undef,-1,'odd'),'123.5'); - -# see if rounding is 'sticky' -$x = $mbf->new('123.4567'); -$y = $x->copy()->bround(); # no-op since nowhere A or P defined - -ok ($y,123.4567); -$y = $x->copy()->round(5); -ok ($y->accuracy(),5); -ok_undef ($y->precision()); # A has precedence, so P still unset -$y = $x->copy()->round(undef,2); -ok ($y->precision(),2); -ok_undef ($y->accuracy()); # P has precedence, so A still unset - -# see if setting A clears P and vice versa -$x = $mbf->new('123.4567'); -ok ($x,'123.4567'); -ok ($x->accuracy(4),4); -ok ($x->precision(-2),-2); # clear A -ok_undef ($x->accuracy()); - -$x = $mbf->new('123.4567'); -ok ($x,'123.4567'); -ok ($x->precision(-2),-2); -ok ($x->accuracy(4),4); # clear P -ok_undef ($x->precision()); - -# does copy work? -$x = $mbf->new(123.456); $x->accuracy(4); $x->precision(2); -$z = $x->copy(); ok_undef ($z->accuracy(),undef); ok ($z->precision(),2); - -# does $x->bdiv($y,d) work when $d > div_scale? -$x = $mbf->new('0.008'); $x->accuracy(8); - -for my $e ( 4, 8, 16, 32 ) - { - print "# Tried: $x->bdiv(3,$e)\n" - unless ok (scalar $x->copy()->bdiv(3,$e), '0.002' . ('6' x ($e-2)) . '7'); - } - -# does accuracy()/precision work on zeros? -foreach my $c ($mbi,$mbf) - { - $x = $c->bzero(); $x->accuracy(5); ok ($x->{_a},5); - $x = $c->bzero(); $x->precision(5); ok ($x->{_p},5); - $x = $c->new(0); $x->accuracy(5); ok ($x->{_a},5); - $x = $c->new(0); $x->precision(5); ok ($x->{_p},5); - - $x = $c->bzero(); $x->round(5); ok ($x->{_a},5); - $x = $c->bzero(); $x->round(undef,5); ok ($x->{_p},5); - $x = $c->new(0); $x->round(5); ok ($x->{_a},5); - $x = $c->new(0); $x->round(undef,5); ok ($x->{_p},5); - - # see if trying to increasing A in bzero() doesn't do something - $x = $c->bzero(); $x->{_a} = 3; $x->round(5); ok ($x->{_a},3); - } - -############################################################################### -# test whether an opp calls objectify properly or not (or at least does what -# it should do given non-objects, w/ or w/o objectify()) - -foreach my $c ($mbi,$mbf) - { -# ${"$c\::precision"} = undef; # reset -# ${"$c\::accuracy"} = undef; # reset - - ok ($c->new(123)->badd(123),246); - ok ($c->badd(123,321),444); - ok ($c->badd(123,$c->new(321)),444); - - ok ($c->new(123)->bsub(122),1); - ok ($c->bsub(321,123),198); - ok ($c->bsub(321,$c->new(123)),198); - - ok ($c->new(123)->bmul(123),15129); - ok ($c->bmul(123,123),15129); - ok ($c->bmul(123,$c->new(123)),15129); - -# ok ($c->new(15129)->bdiv(123),123); -# ok ($c->bdiv(15129,123),123); -# ok ($c->bdiv(15129,$c->new(123)),123); - - ok ($c->new(15131)->bmod(123),2); - ok ($c->bmod(15131,123),2); - ok ($c->bmod(15131,$c->new(123)),2); - - ok ($c->new(2)->bpow(16),65536); - ok ($c->bpow(2,16),65536); - ok ($c->bpow(2,$c->new(16)),65536); - - ok ($c->new(2**15)->brsft(1),2**14); - ok ($c->brsft(2**15,1),2**14); - ok ($c->brsft(2**15,$c->new(1)),2**14); - - ok ($c->new(2**13)->blsft(1),2**14); - ok ($c->blsft(2**13,1),2**14); - ok ($c->blsft(2**13,$c->new(1)),2**14); - } - -############################################################################### -# test wether operations round properly afterwards -# These tests are not complete, since they do not excercise every "return" -# statement in the op's. But heh, it's better than nothing... - -$x = $mbf->new('123.456'); -$y = $mbf->new('654.321'); -$x->{_a} = 5; # $x->accuracy(5) would round $x straightaway -$y->{_a} = 4; # $y->accuracy(4) would round $x straightaway - -$z = $x + $y; ok ($z,'777.8'); -$z = $y - $x; ok ($z,'530.9'); -$z = $y * $x; ok ($z,'80780'); -$z = $x ** 2; ok ($z,'15241'); -$z = $x * $x; ok ($z,'15241'); - -# not: $z = -$x; ok ($z,'-123.46'); ok ($x,'123.456'); -$z = $x->copy(); $z->{_a} = 2; $z = $z / 2; ok ($z,62); -$x = $mbf->new(123456); $x->{_a} = 4; -$z = $x->copy; $z++; ok ($z,123500); - -$x = $mbi->new(123456); -$y = $mbi->new(654321); -$x->{_a} = 5; # $x->accuracy(5) would round $x straightaway -$y->{_a} = 4; # $y->accuracy(4) would round $x straightaway - -$z = $x + $y; ok ($z,777800); -$z = $y - $x; ok ($z,530900); -$z = $y * $x; ok ($z,80780000000); -$z = $x ** 2; ok ($z,15241000000); -# not yet: $z = -$x; ok ($z,-123460); ok ($x,123456); -$z = $x->copy; $z++; ok ($z,123460); -$z = $x->copy(); $z->{_a} = 2; $z = $z / 2; ok ($z,62000); - -$x = $mbi->new(123400); $x->{_a} = 4; -ok ($x->bnot(),-123400); # not -1234001 - -# both babs() and bneg() don't need to round, since the input will already -# be rounded (either as $x or via new($string)), and they don't change the -# value. The two tests below peek at this by using _a (illegally) directly -$x = $mbi->new(-123401); $x->{_a} = 4; ok ($x->babs(),123401); -$x = $mbi->new(-123401); $x->{_a} = 4; ok ($x->bneg(),123401); - -# test fdiv rounding to A and R (bug in v1.48 and maybe earlier versions) -$mbf->round_mode('even'); -$x = $mbf->new('740.7')->fdiv('6',4,undef,'zero'); ok ($x,'123.4'); - -$x = $mbi->new('123456'); $y = $mbi->new('123456'); $y->{_a} = 6; -ok ($x->bdiv($y),1); ok ($x->{_a},6); # carried over - -$x = $mbi->new('123456'); $y = $mbi->new('123456'); $x->{_a} = 6; -ok ($x->bdiv($y),1); ok ($x->{_a},6); # carried over - -$x = $mbi->new('123456'); $y = $mbi->new('223456'); $y->{_a} = 6; -ok ($x->bdiv($y),0); ok ($x->{_a},6); # carried over - -$x = $mbi->new('123456'); $y = $mbi->new('223456'); $x->{_a} = 6; -ok ($x->bdiv($y),0); ok ($x->{_a},6); # carried over - -############################################################################### -# test that bop(0) does the same than bop(undef) - -$x = $mbf->new('1234567890'); -ok ($x->copy()->bsqrt(0),$x->copy()->bsqrt(undef)); -ok ($x->copy->bsqrt(0),'35136.41828644462161665823116758077037159'); - -ok_undef ($x->{_a}); - -# test that bsqrt() modifies $x and does not just return something else -# (especially under BareCalc) -$z = $x->bsqrt(); -ok ($z,$x); ok ($x,'35136.41828644462161665823116758077037159'); - -$x = $mbf->new('1.234567890123456789'); -ok ($x->copy()->bpow('0.5',0),$x->copy()->bpow('0.5',undef)); -ok ($x->copy()->bpow('0.5',0),$x->copy()->bsqrt(undef)); -ok ($x->copy()->bpow('2',0),'1.524157875323883675019051998750190521'); - -############################################################################### -# test (also under Bare) that bfac() rounds at last step - -ok ($mbi->new(12)->bfac(),'479001600'); -ok ($mbi->new(12)->bfac(2),'480000000'); -$x = $mbi->new(12); $x->accuracy(2); ok ($x->bfac(),'480000000'); -$x = $mbi->new(13); $x->accuracy(2); ok ($x->bfac(),'6200000000'); -$x = $mbi->new(13); $x->accuracy(3); ok ($x->bfac(),'6230000000'); -$x = $mbi->new(13); $x->accuracy(4); ok ($x->bfac(),'6227000000'); -# this does 1,2,3...9,10,11,12...20 -$x = $mbi->new(20); $x->accuracy(1); ok ($x->bfac(),'2000000000000000000'); - -############################################################################### -# test bsqrt) rounding to given A/P/R (bug prior to v1.60) -$x = $mbi->new('123456')->bsqrt(2,undef); ok ($x,'350'); # not 351 -$x = $mbi->new('3')->bsqrt(2,undef); ok ($x->accuracy(),2); - -$mbi->round_mode('even'); $x = $mbi->new('126025')->bsqrt(2,undef,'+inf'); -ok ($x,'360'); # not 355 nor 350 - -$x = $mbi->new('126025')->bsqrt(undef,2); ok ($x,'400'); # not 355 - - -############################################################################### -# test mixed arguments - -$x = $mbf->new(10); -$u = $mbf->new(2.5); -$y = $mbi->new(2); - -$z = $x + $y; ok ($z,12); ok (ref($z),$mbf); -$z = $x / $y; ok ($z,5); ok (ref($z),$mbf); -$z = $u * $y; ok ($z,5); ok (ref($z),$mbf); - -$y = $mbi->new(12345); -$z = $u->copy()->bmul($y,2,undef,'odd'); ok ($z,31000); -$z = $u->copy()->bmul($y,3,undef,'odd'); ok ($z,30900); -$z = $u->copy()->bmul($y,undef,0,'odd'); ok ($z,30863); -$z = $u->copy()->bmul($y,undef,1,'odd'); ok ($z,30863); -$z = $u->copy()->bmul($y,undef,2,'odd'); ok ($z,30860); -$z = $u->copy()->bmul($y,undef,3,'odd'); ok ($z,30900); -$z = $u->copy()->bmul($y,undef,-1,'odd'); ok ($z,30862.5); - -my $warn = ''; $SIG{__WARN__} = sub { $warn = shift; }; -# these should no longer warn, even tho '3.17' is a NaN in BigInt (>= returns -# now false, bug until v1.80) -$warn = ''; eval "\$z = 3.17 <= \$y"; ok ($z, ''); -print "# Got: '$warn'\n" unless -ok ($warn !~ /^Use of uninitialized value (\$y )?(in numeric le \(<=\) |)at/); -$warn = ''; eval "\$z = \$y >= 3.17"; ok ($z, ''); -print "# Got: '$warn'\n" unless -ok ($warn !~ /^Use of uninitialized value (\$y )?(in numeric ge \(>=\) |)at/); - -# XXX TODO breakage: -# $z = $y->copy()->bmul($u,2,0,'odd'); ok ($z,31000); -# $z = $y * $u; ok ($z,5); ok (ref($z),$mbi); -# $z = $y + $x; ok ($z,12); ok (ref($z),$mbi); -# $z = $y / $x; ok ($z,0); ok (ref($z),$mbi); - -############################################################################### -# rounding in bdiv with fallback and already set A or P - -{ - no strict 'refs'; - ${"$mbf\::accuracy"} = undef; - ${"$mbf\::precision"} = undef; - ${"$mbf\::div_scale"} = 40; -} - - $x = $mbf->new(10); $x->{_a} = 4; - ok ($x->bdiv(3),'3.333'); - ok ($x->{_a},4); # set's it since no fallback - -$x = $mbf->new(10); $x->{_a} = 4; $y = $mbf->new(3); -ok ($x->bdiv($y),'3.333'); -ok ($x->{_a},4); # set's it since no fallback - -# rounding to P of x -$x = $mbf->new(10); $x->{_p} = -2; -ok ($x->bdiv(3),'3.33'); - -# round in div with requested P -$x = $mbf->new(10); -ok ($x->bdiv(3,undef,-2),'3.33'); - -# round in div with requested P greater than fallback -{ - no strict 'refs'; - ${"$mbf\::div_scale"} = 5; - $x = $mbf->new(10); - ok ($x->bdiv(3,undef,-8),'3.33333333'); - ${"$mbf\::div_scale"} = 40; -} - -$x = $mbf->new(10); $y = $mbf->new(3); $y->{_a} = 4; -ok ($x->bdiv($y),'3.333'); -ok ($x->{_a},4); ok ($y->{_a},4); # set's it since no fallback -ok_undef ($x->{_p}); ok_undef ($y->{_p}); - -# rounding to P of y -$x = $mbf->new(10); $y = $mbf->new(3); $y->{_p} = -2; -ok ($x->bdiv($y),'3.33'); -ok ($x->{_p},-2); - ok ($y->{_p},-2); -ok_undef ($x->{_a}); ok_undef ($y->{_a}); - -############################################################################### -# test whether bround(-n) fails in MBF (undocumented in MBI) -eval { $x = $mbf->new(1); $x->bround(-2); }; -ok ($@ =~ /^bround\(\) needs positive accuracy/,1); - -# test whether rounding to higher accuracy is no-op -$x = $mbf->new(1); $x->{_a} = 4; -ok ($x,'1.000'); -$x->bround(6); # must be no-op -ok ($x->{_a},4); -ok ($x,'1.000'); - -$x = $mbi->new(1230); $x->{_a} = 3; -ok ($x,'1230'); -$x->bround(6); # must be no-op -ok ($x->{_a},3); -ok ($x,'1230'); - -# bround(n) should set _a -$x->bround(2); # smaller works -ok ($x,'1200'); -ok ($x->{_a},2); - -# bround(-n) is undocumented and only used by MBF -# bround(-n) should set _a -$x = $mbi->new(12345); -$x->bround(-1); -ok ($x,'12300'); -ok ($x->{_a},4); - -# bround(-n) should set _a -$x = $mbi->new(12345); -$x->bround(-2); -ok ($x,'12000'); -ok ($x->{_a},3); - -# bround(-n) should set _a -$x = $mbi->new(12345); $x->{_a} = 5; -$x->bround(-3); -ok ($x,'10000'); -ok ($x->{_a},2); - -# bround(-n) should set _a -$x = $mbi->new(12345); $x->{_a} = 5; -$x->bround(-4); -ok ($x,'0'); -ok ($x->{_a},1); - -# bround(-n) should be noop if n too big -$x = $mbi->new(12345); -$x->bround(-5); -ok ($x,'0'); # scale to "big" => 0 -ok ($x->{_a},0); - -# bround(-n) should be noop if n too big -$x = $mbi->new(54321); -$x->bround(-5); -ok ($x,'100000'); # used by MBF to round 0.0054321 at 0.0_6_00000 -ok ($x->{_a},0); - -# bround(-n) should be noop if n too big -$x = $mbi->new(54321); $x->{_a} = 5; -$x->bround(-6); -ok ($x,'100000'); # no-op -ok ($x->{_a},0); - -# bround(n) should set _a -$x = $mbi->new(12345); $x->{_a} = 5; -$x->bround(5); # must be no-op -ok ($x,'12345'); -ok ($x->{_a},5); - -# bround(n) should set _a -$x = $mbi->new(12345); $x->{_a} = 5; -$x->bround(6); # must be no-op -ok ($x,'12345'); - -$x = $mbf->new('0.0061'); $x->bfround(-2); ok ($x,'0.01'); -$x = $mbf->new('0.004'); $x->bfround(-2); ok ($x,'0.00'); -$x = $mbf->new('0.005'); $x->bfround(-2); ok ($x,'0.00'); - -$x = $mbf->new('12345'); $x->bfround(2); ok ($x,'12340'); -$x = $mbf->new('12340'); $x->bfround(2); ok ($x,'12340'); - -# MBI::bfround should clear A for negative P -$x = $mbi->new('1234'); $x->accuracy(3); $x->bfround(-2); -ok_undef ($x->{_a}); - -# test that bfround() and bround() work with large numbers - -$x = $mbf->new(1)->bdiv(5678,undef,-63); -ok ($x, '0.000176118351532229658330398027474462839027826699542092286016203'); - -$x = $mbf->new(1)->bdiv(5678,undef,-90); -ok ($x, '0.000176118351532229658330398027474462839027826699542092286016202888340965128566396618527651'); - -$x = $mbf->new(1)->bdiv(5678,80); -ok ($x, '0.00017611835153222965833039802747446283902782669954209228601620288834096512856639662'); - -############################################################################### -# rounding with already set precision/accuracy - -$x = $mbf->new(1); $x->{_p} = -5; -ok ($x,'1.00000'); - -# further rounding donw -ok ($x->bfround(-2),'1.00'); -ok ($x->{_p},-2); - -$x = $mbf->new(12345); $x->{_a} = 5; -ok ($x->bround(2),'12000'); -ok ($x->{_a},2); - -$x = $mbf->new('1.2345'); $x->{_a} = 5; -ok ($x->bround(2),'1.2'); -ok ($x->{_a},2); - -# mantissa/exponent format and A/P -$x = $mbf->new('12345.678'); $x->accuracy(4); -ok ($x,'12350'); ok ($x->{_a},4); ok_undef ($x->{_p}); - -#ok_undef ($x->{_m}->{_a}); ok_undef ($x->{_e}->{_a}); -#ok_undef ($x->{_m}->{_p}); ok_undef ($x->{_e}->{_p}); - -# check for no A/P in case of fallback -# result -$x = $mbf->new(100) / 3; -ok_undef ($x->{_a}); ok_undef ($x->{_p}); - -# result & reminder -$x = $mbf->new(100) / 3; ($x,$y) = $x->bdiv(3); -ok_undef ($x->{_a}); ok_undef ($x->{_p}); -ok_undef ($y->{_a}); ok_undef ($y->{_p}); - -############################################################################### -# math with two numbers with differen A and P - -$x = $mbf->new(12345); $x->accuracy(4); # '12340' -$y = $mbf->new(12345); $y->accuracy(2); # '12000' -ok ($x+$y,24000); # 12340+12000=> 24340 => 24000 - -$x = $mbf->new(54321); $x->accuracy(4); # '12340' -$y = $mbf->new(12345); $y->accuracy(3); # '12000' -ok ($x-$y,42000); # 54320+12300=> 42020 => 42000 - -$x = $mbf->new('1.2345'); $x->precision(-2); # '1.23' -$y = $mbf->new('1.2345'); $y->precision(-4); # '1.2345' -ok ($x+$y,'2.46'); # 1.2345+1.2300=> 2.4645 => 2.46 - -############################################################################### -# round should find and use proper class - -#$x = Foo->new(); -#ok ($x->round($Foo::accuracy),'a' x $Foo::accuracy); -#ok ($x->round(undef,$Foo::precision),'p' x $Foo::precision); -#ok ($x->bfround($Foo::precision),'p' x $Foo::precision); -#ok ($x->bround($Foo::accuracy),'a' x $Foo::accuracy); - -############################################################################### -# find out whether _find_round_parameters is doing what's it's supposed to do - -{ - no strict 'refs'; - ${"$mbi\::accuracy"} = undef; - ${"$mbi\::precision"} = undef; - ${"$mbi\::div_scale"} = 40; - ${"$mbi\::round_mode"} = 'odd'; -} - -$x = $mbi->new(123); -my @params = $x->_find_round_parameters(); -ok (scalar @params,1); # nothing to round - -@params = $x->_find_round_parameters(1); -ok (scalar @params,4); # a=1 -ok ($params[0],$x); # self -ok ($params[1],1); # a -ok_undef ($params[2]); # p -ok ($params[3],'odd'); # round_mode - -@params = $x->_find_round_parameters(undef,2); -ok (scalar @params,4); # p=2 -ok ($params[0],$x); # self -ok_undef ($params[1]); # a -ok ($params[2],2); # p -ok ($params[3],'odd'); # round_mode - -eval { @params = $x->_find_round_parameters(undef,2,'foo'); }; -ok ($@ =~ /^Unknown round mode 'foo'/,1); - -@params = $x->_find_round_parameters(undef,2,'+inf'); -ok (scalar @params,4); # p=2 -ok ($params[0],$x); # self -ok_undef ($params[1]); # a -ok ($params[2],2); # p -ok ($params[3],'+inf'); # round_mode - -@params = $x->_find_round_parameters(2,-2,'+inf'); -ok (scalar @params,1); # error, A and P defined -ok ($params[0],$x); # self - -{ - no strict 'refs'; - ${"$mbi\::accuracy"} = 1; - @params = $x->_find_round_parameters(undef,-2); - ok (scalar @params,1); # error, A and P defined - ok ($params[0],$x); # self - ok ($x->is_nan(),1); # and must be NaN - - ${"$mbi\::accuracy"} = undef; - ${"$mbi\::precision"} = 1; - @params = $x->_find_round_parameters(1,undef); - ok (scalar @params,1); # error, A and P defined - ok ($params[0],$x); # self - ok ($x->is_nan(),1); # and must be NaN - - ${"$mbi\::precision"} = undef; # reset -} - -############################################################################### -# test whether bone/bzero take additional A & P, or reset it etc - -foreach my $c ($mbi,$mbf) - { - $x = $c->new(2)->bzero(); ok_undef ($x->{_a}); ok_undef ($x->{_p}); - $x = $c->new(2)->bone(); ok_undef ($x->{_a}); ok_undef ($x->{_p}); - $x = $c->new(2)->binf(); ok_undef ($x->{_a}); ok_undef ($x->{_p}); - $x = $c->new(2)->bnan(); ok_undef ($x->{_a}); ok_undef ($x->{_p}); - - $x = $c->new(2); $x->{_a} = 1; $x->{_p} = 2; $x->bnan(); - ok_undef ($x->{_a}); ok_undef ($x->{_p}); - $x = $c->new(2); $x->{_a} = 1; $x->{_p} = 2; $x->binf(); - ok_undef ($x->{_a}); ok_undef ($x->{_p}); - - $x = $c->new(2,1); ok ($x->{_a},1); ok_undef ($x->{_p}); - $x = $c->new(2,undef,1); ok_undef ($x->{_a}); ok ($x->{_p},1); - - $x = $c->new(2,1)->bzero(); ok ($x->{_a},1); ok_undef ($x->{_p}); - $x = $c->new(2,undef,1)->bzero(); ok_undef ($x->{_a}); ok ($x->{_p},1); - - $x = $c->new(2,1)->bone(); ok ($x->{_a},1); ok_undef ($x->{_p}); - $x = $c->new(2,undef,1)->bone(); ok_undef ($x->{_a}); ok ($x->{_p},1); - - $x = $c->new(2); $x->bone('+',2,undef); ok ($x->{_a},2); ok_undef ($x->{_p}); - $x = $c->new(2); $x->bone('+',undef,2); ok_undef ($x->{_a}); ok ($x->{_p},2); - $x = $c->new(2); $x->bone('-',2,undef); ok ($x->{_a},2); ok_undef ($x->{_p}); - $x = $c->new(2); $x->bone('-',undef,2); ok_undef ($x->{_a}); ok ($x->{_p},2); - - $x = $c->new(2); $x->bzero(2,undef); ok ($x->{_a},2); ok_undef ($x->{_p}); - $x = $c->new(2); $x->bzero(undef,2); ok_undef ($x->{_a}); ok ($x->{_p},2); - } - -############################################################################### -# test whether bone/bzero honour globals - -for my $c ($mbi,$mbf) - { - $c->accuracy(2); - $x = $c->bone(); ok ($x->accuracy(),2); - $x = $c->bzero(); ok ($x->accuracy(),2); - $c->accuracy(undef); - - $c->precision(-2); - $x = $c->bone(); ok ($x->precision(),-2); - $x = $c->bzero(); ok ($x->precision(),-2); - $c->precision(undef); - } - -############################################################################### -# check whether mixing A and P creates a NaN - -# new with set accuracy/precision and with parameters -{ - no strict 'refs'; - foreach my $c ($mbi,$mbf) - { - ok ($c->new(123,4,-3),'NaN'); # with parameters - ${"$c\::accuracy"} = 42; - ${"$c\::precision"} = 2; - ok ($c->new(123),'NaN'); # with globals - ${"$c\::accuracy"} = undef; - ${"$c\::precision"} = undef; - } -} - -# binary ops -foreach my $class ($mbi,$mbf) - { - foreach (qw/add sub mul pow mod/) - #foreach (qw/add sub mul div pow mod/) - { - my $try = "my \$x = $class->new(1234); \$x->accuracy(5); "; - $try .= "my \$y = $class->new(12); \$y->precision(-3); "; - $try .= "\$x->b$_(\$y);"; - $rc = eval $try; - print "# Tried: '$try'\n" if !ok ($rc, 'NaN'); - } - } - -# unary ops -foreach (qw/new bsqrt/) - { - my $try = 'my $x = $mbi->$_(1234,5,-3); '; - $rc = eval $try; - print "# Tried: '$try'\n" if !ok ($rc, 'NaN'); - } - -# see if $x->bsub(0) and $x->badd(0) really round -foreach my $class ($mbi,$mbf) - { - $x = $class->new(123); $class->accuracy(2); $x->bsub(0); - ok ($x,120); - $class->accuracy(undef); - $x = $class->new(123); $class->accuracy(2); $x->badd(0); - ok ($x,120); - $class->accuracy(undef); - } - -############################################################################### -# test whether shortcuts returning zero/one preserve A and P - -my ($ans1,$f,$a,$p,$xp,$yp,$xa,$ya,$try,$ans,@args); -my $CALC = Math::BigInt->config()->{lib}; -while (<DATA>) - { - $_ =~ s/[\n\r]//g; # remove newlines - next if /^\s*(#|$)/; # skip comments and empty lines - if (s/^&//) - { - $f = $_; next; # function - } - @args = split(/:/,$_,99); - my $ans = pop(@args); - - ($x,$xa,$xp) = split (/,/,$args[0]); - $xa = $xa || ''; $xp = $xp || ''; - $try = "\$x = $mbi->new('$x'); "; - $try .= "\$x->accuracy($xa); " if $xa ne ''; - $try .= "\$x->precision($xp); " if $xp ne ''; - - ($y,$ya,$yp) = split (/,/,$args[1]); - $ya = $ya || ''; $yp = $yp || ''; - $try .= "\$y = $mbi->new('$y'); "; - $try .= "\$y->accuracy($ya); " if $ya ne ''; - $try .= "\$y->precision($yp); " if $yp ne ''; - - $try .= "\$x->$f(\$y);"; - - # print "trying $try\n"; - $rc = eval $try; - # convert hex/binary targets to decimal - if ($ans =~ /^(0x0x|0b0b)/) - { - $ans =~ s/^0[xb]//; - $ans = $mbi->new($ans)->bstr(); - } - print "# Tried: '$try'\n" if !ok ($rc, $ans); - # check internal state of number objects - is_valid($rc,$f) if ref $rc; - - # now check whether A and P are set correctly - # only one of $a or $p will be set (no crossing here) - $a = $xa || $ya; $p = $xp || $yp; - - # print "Check a=$a p=$p\n"; - # print "# Tried: '$try'\n"; - if ($a ne '') - { - if (!(ok ($x->{_a}, $a) && ok_undef ($x->{_p}))) - { - print "# Check: A=$a and P=undef\n"; - print "# Tried: '$try'\n"; - } - } - if ($p ne '') - { - if (!(ok ($x->{_p}, $p) && ok_undef ($x->{_a}))) - { - print "# Check: A=undef and P=$p\n"; - print "# Tried: '$try'\n"; - } - } - } - -# all done -1; - -############################################################################### -############################################################################### -# Perl 5.005 does not like ok ($x,undef) - -sub ok_undef - { - my $x = shift; - - ok (1,1) and return 1 if !defined $x; - ok ($x,'undef'); - print "# Called from ",join(' ',caller()),"\n"; - return 0; - } - -############################################################################### -# sub to check validity of a BigInt internally, to ensure that no op leaves a -# number object in an invalid state (f.i. "-0") - -sub is_valid - { - my ($x,$f) = @_; - - my $e = 0; # error? - # ok as reference? - $e = 'Not a reference' 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)$/; - - $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'); - - ok (1,$e." after op '$f'"); - } - -# format is: -# x,A,P:x,A,P:result -# 123,,3 means 123 with precision 3 (A is undef) -# the A or P of the result is calculated automatically -__DATA__ -&badd -123,,:123,,:246 -123,3,:0,,:123 -123,,-3:0,,:123 -123,,:0,3,:123 -123,,:0,,-3:123 -&bmul -123,,:1,,:123 -123,3,:0,,:0 -123,,-3:0,,:0 -123,,:0,3,:0 -123,,:0,,-3:0 -123,3,:1,,:123 -123,,-3:1,,:123 -123,,:1,3,:123 -123,,:1,,-3:123 -1,3,:123,,:123 -1,,-3:123,,:123 -1,,:123,3,:123 -1,,:123,,-3:123 -&bdiv -123,,:1,,:123 -123,4,:1,,:123 -123,,:1,4,:123 -123,,:1,,-4:123 -123,,-4:1,,:123 -1,4,:123,,:0 -1,,:123,4,:0 -1,,:123,,-4:0 -1,,-4:123,,:0 -&band -1,,:3,,:1 -1234,1,:0,,:0 -1234,,:0,1,:0 -1234,,-1:0,,:0 -1234,,:0,,-1:0 -0xFF,,:0x10,,:0x0x10 -0xFF,2,:0xFF,,:250 -0xFF,,:0xFF,2,:250 -0xFF,,1:0xFF,,:250 -0xFF,,:0xFF,,1:250 -&bxor -1,,:3,,:2 -1234,1,:0,,:1000 -1234,,:0,1,:1000 -1234,,3:0,,:1000 -1234,,:0,,3:1000 -0xFF,,:0x10,,:239 -# 250 ^ 255 => 5 -0xFF,2,:0xFF,,:5 -0xFF,,:0xFF,2,:5 -0xFF,,1:0xFF,,:5 -0xFF,,:0xFF,,1:5 -# 250 ^ 4095 = 3845 => 3800 -0xFF,2,:0xFFF,,:3800 -# 255 ^ 4100 = 4347 => 4300 -0xFF,,:0xFFF,2,:4300 -0xFF,,2:0xFFF,,:3800 -# 255 ^ 4100 = 10fb => 4347 => 4300 -0xFF,,:0xFFF,,2:4300 -&bior -1,,:3,,:3 -1234,1,:0,,:1000 -1234,,:0,1,:1000 -1234,,3:0,,:1000 -1234,,:0,,3:1000 -0xFF,,:0x10,,:0x0xFF -# FF | FA = FF => 250 -250,2,:0xFF,,:250 -0xFF,,:250,2,:250 -0xFF,,1:0xFF,,:250 -0xFF,,:0xFF,,1:250 -&bpow -2,,:3,,:8 -2,,:0,,:1 -2,2,:0,,:1 -2,,:0,2,:1 |