1 # test rounding, accuracy, precicion and fallback, round_mode and mixing
4 # Make sure you always quote any bare floating-point values, lest 123.46 will
5 # be stringified to 123.4599999999 due to limited float prevision.
10 ###############################################################################
11 # test defaults and set/get
15 ok_undef (${"$mbi\::accuracy"});
16 ok_undef (${"$mbi\::precision"});
17 ok_undef ($mbi->accuracy());
18 ok_undef ($mbi->precision());
19 ok (${"$mbi\::div_scale"},40);
20 ok (${"$mbi\::round_mode"},'even');
21 ok ($mbi->round_mode(),'even');
23 ok_undef (${"$mbf\::accuracy"});
24 ok_undef (${"$mbf\::precision"});
25 ok_undef ($mbf->precision());
26 ok_undef ($mbf->precision());
27 ok (${"$mbf\::div_scale"},40);
28 ok (${"$mbf\::round_mode"},'even');
29 ok ($mbf->round_mode(),'even');
33 foreach my $class ($mbi,$mbf)
35 ok_undef ($class->accuracy());
36 ok_undef ($class->precision());
37 ok ($class->round_mode(),'even');
38 ok ($class->div_scale(),40);
40 ok ($class->div_scale(20),20);
41 $class->div_scale(40); ok ($class->div_scale(),40);
43 ok ($class->round_mode('odd'),'odd');
44 $class->round_mode('even'); ok ($class->round_mode(),'even');
46 ok ($class->accuracy(2),2);
47 $class->accuracy(3); ok ($class->accuracy(),3);
48 ok_undef ($class->accuracy(undef));
50 ok ($class->precision(2),2);
51 ok ($class->precision(-2),-2);
52 $class->precision(3); ok ($class->precision(),3);
53 ok_undef ($class->precision(undef));
59 foreach (qw/5 42 -1 0/)
61 ok (${"$mbf\::accuracy"} = $_,$_);
62 ok (${"$mbi\::accuracy"} = $_,$_);
64 ok_undef (${"$mbf\::accuracy"} = undef);
65 ok_undef (${"$mbi\::accuracy"} = undef);
68 foreach (qw/5 42 -1 0/)
70 ok (${"$mbf\::precision"} = $_,$_);
71 ok (${"$mbi\::precision"} = $_,$_);
73 ok_undef (${"$mbf\::precision"} = undef);
74 ok_undef (${"$mbi\::precision"} = undef);
79 ok (${"$mbf\::div_scale"} = $_,$_);
80 ok (${"$mbi\::div_scale"} = $_,$_);
82 # illegal values are possible for fallback due to no accessor
85 foreach (qw/odd even zero trunc +inf -inf/)
87 ok (${"$mbf\::round_mode"} = $_,$_);
88 ok (${"$mbi\::round_mode"} = $_,$_);
90 ${"$mbf\::round_mode"} = 'zero';
91 ok (${"$mbf\::round_mode"},'zero');
92 ok (${"$mbi\::round_mode"},'-inf'); # from above
94 # reset for further tests
95 ${"$mbi\::accuracy"} = undef;
96 ${"$mbi\::precision"} = undef;
97 ${"$mbf\::div_scale"} = 40;
101 $x = $mbf->new('123.456');
102 ok_undef ($x->accuracy());
103 ok ($x->accuracy(5),5);
104 ok_undef ($x->accuracy(undef),undef);
105 ok_undef ($x->precision());
106 ok ($x->precision(5),5);
107 ok_undef ($x->precision(undef),undef);
111 # see if MBF changes MBIs values
112 ok (${"$mbi\::accuracy"} = 42,42);
113 ok (${"$mbf\::accuracy"} = 64,64);
114 ok (${"$mbi\::accuracy"},42); # should be still 42
115 ok (${"$mbf\::accuracy"},64); # should be now 64
118 ###############################################################################
119 # see if creating a number under set A or P will round it
123 ${"$mbi\::accuracy"} = 4;
124 ${"$mbi\::precision"} = undef;
126 ok ($mbi->new(123456),123500); # with A
127 ${"$mbi\::accuracy"} = undef;
128 ${"$mbi\::precision"} = 3;
129 ok ($mbi->new(123456),123000); # with P
131 ${"$mbf\::accuracy"} = 4;
132 ${"$mbf\::precision"} = undef;
133 ${"$mbi\::precision"} = undef;
135 ok ($mbf->new('123.456'),'123.5'); # with A
136 ${"$mbf\::accuracy"} = undef;
137 ${"$mbf\::precision"} = -1;
138 ok ($mbf->new('123.456'),'123.5'); # with P from MBF, not MBI!
140 ${"$mbf\::precision"} = undef; # reset
143 ###############################################################################
144 # see if MBI leaves MBF's private parts alone
148 ${"$mbi\::precision"} = undef; ${"$mbf\::precision"} = undef;
149 ${"$mbi\::accuracy"} = 4; ${"$mbf\::accuracy"} = undef;
150 ok ($mbf->new('123.456'),'123.456');
151 ${"$mbi\::accuracy"} = undef; # reset
154 ###############################################################################
155 # see if setting accuracy/precision actually rounds the number
157 $x = $mbf->new('123.456'); $x->accuracy(4); ok ($x,'123.5');
158 $x = $mbf->new('123.456'); $x->precision(-2); ok ($x,'123.46');
160 $x = $mbi->new(123456); $x->accuracy(4); ok ($x,123500);
161 $x = $mbi->new(123456); $x->precision(2); ok ($x,123500);
163 ###############################################################################
164 # test actual rounding via round()
166 $x = $mbf->new('123.456');
167 ok ($x->copy()->round(5),'123.46');
168 ok ($x->copy()->round(4),'123.5');
169 ok ($x->copy()->round(5,2),'NaN');
170 ok ($x->copy()->round(undef,-2),'123.46');
171 ok ($x->copy()->round(undef,2),120);
173 $x = $mbi->new('123');
174 ok ($x->round(5,2),'NaN');
176 $x = $mbf->new('123.45000');
177 ok ($x->copy()->round(undef,-1,'odd'),'123.5');
179 # see if rounding is 'sticky'
180 $x = $mbf->new('123.4567');
181 $y = $x->copy()->bround(); # no-op since nowhere A or P defined
184 $y = $x->copy()->round(5);
185 ok ($y->accuracy(),5);
186 ok_undef ($y->precision()); # A has precedence, so P still unset
187 $y = $x->copy()->round(undef,2);
188 ok ($y->precision(),2);
189 ok_undef ($y->accuracy()); # P has precedence, so A still unset
191 # see if setting A clears P and vice versa
192 $x = $mbf->new('123.4567');
194 ok ($x->accuracy(4),4);
195 ok ($x->precision(-2),-2); # clear A
196 ok_undef ($x->accuracy());
198 $x = $mbf->new('123.4567');
200 ok ($x->precision(-2),-2);
201 ok ($x->accuracy(4),4); # clear P
202 ok_undef ($x->precision());
205 $x = $mbf->new(123.456); $x->accuracy(4); $x->precision(2);
206 $z = $x->copy(); ok_undef ($z->accuracy(),undef); ok ($z->precision(),2);
208 # does $x->bdiv($y,d) work when $d > div_scale?
209 $x = $mbf->new('0.008'); $x->accuracy(8);
211 for my $e ( 4, 8, 16, 32 )
213 print "# Tried: $x->bdiv(3,$e)\n"
214 unless ok (scalar $x->copy()->bdiv(3,$e), '0.002' . ('6' x ($e-2)) . '7');
217 # does accuracy()/precision work on zeros?
218 foreach my $c ($mbi,$mbf)
220 $x = $c->bzero(); $x->accuracy(5); ok ($x->{_a},5);
221 $x = $c->bzero(); $x->precision(5); ok ($x->{_p},5);
222 $x = $c->new(0); $x->accuracy(5); ok ($x->{_a},5);
223 $x = $c->new(0); $x->precision(5); ok ($x->{_p},5);
225 $x = $c->bzero(); $x->round(5); ok ($x->{_a},5);
226 $x = $c->bzero(); $x->round(undef,5); ok ($x->{_p},5);
227 $x = $c->new(0); $x->round(5); ok ($x->{_a},5);
228 $x = $c->new(0); $x->round(undef,5); ok ($x->{_p},5);
230 # see if trying to increasing A in bzero() doesn't do something
231 $x = $c->bzero(); $x->{_a} = 3; $x->round(5); ok ($x->{_a},3);
234 ###############################################################################
235 # test whether an opp calls objectify properly or not (or at least does what
236 # it should do given non-objects, w/ or w/o objectify())
238 foreach my $c ($mbi,$mbf)
240 # ${"$c\::precision"} = undef; # reset
241 # ${"$c\::accuracy"} = undef; # reset
243 ok ($c->new(123)->badd(123),246);
244 ok ($c->badd(123,321),444);
245 ok ($c->badd(123,$c->new(321)),444);
247 ok ($c->new(123)->bsub(122),1);
248 ok ($c->bsub(321,123),198);
249 ok ($c->bsub(321,$c->new(123)),198);
251 ok ($c->new(123)->bmul(123),15129);
252 ok ($c->bmul(123,123),15129);
253 ok ($c->bmul(123,$c->new(123)),15129);
255 # ok ($c->new(15129)->bdiv(123),123);
256 # ok ($c->bdiv(15129,123),123);
257 # ok ($c->bdiv(15129,$c->new(123)),123);
259 ok ($c->new(15131)->bmod(123),2);
260 ok ($c->bmod(15131,123),2);
261 ok ($c->bmod(15131,$c->new(123)),2);
263 ok ($c->new(2)->bpow(16),65536);
264 ok ($c->bpow(2,16),65536);
265 ok ($c->bpow(2,$c->new(16)),65536);
267 # ok ($c->new(2**15)->brsft(1),2**14);
268 # ok ($c->brsft(2**15,1),2**14);
269 # ok ($c->brsft(2**15,$c->new(1)),2**14);
271 ok ($c->new(2**13)->blsft(1),2**14);
272 ok ($c->blsft(2**13,1),2**14);
273 ok ($c->blsft(2**13,$c->new(1)),2**14);
276 ###############################################################################
277 # test wether operations round properly afterwards
278 # These tests are not complete, since they do not excercise every "return"
279 # statement in the op's. But heh, it's better than nothing...
281 $x = $mbf->new('123.456');
282 $y = $mbf->new('654.321');
283 $x->{_a} = 5; # $x->accuracy(5) would round $x straightaway
284 $y->{_a} = 4; # $y->accuracy(4) would round $x straightaway
286 $z = $x + $y; ok ($z,'777.8');
287 $z = $y - $x; ok ($z,'530.9');
288 $z = $y * $x; ok ($z,'80780');
289 $z = $x ** 2; ok ($z,'15241');
290 $z = $x * $x; ok ($z,'15241');
292 # not: $z = -$x; ok ($z,'-123.46'); ok ($x,'123.456');
293 $z = $x->copy(); $z->{_a} = 2; $z = $z / 2; ok ($z,62);
294 $x = $mbf->new(123456); $x->{_a} = 4;
295 $z = $x->copy; $z++; ok ($z,123500);
297 $x = $mbi->new(123456);
298 $y = $mbi->new(654321);
299 $x->{_a} = 5; # $x->accuracy(5) would round $x straightaway
300 $y->{_a} = 4; # $y->accuracy(4) would round $x straightaway
302 $z = $x + $y; ok ($z,777800);
303 $z = $y - $x; ok ($z,530900);
304 $z = $y * $x; ok ($z,80780000000);
305 $z = $x ** 2; ok ($z,15241000000);
306 # not yet: $z = -$x; ok ($z,-123460); ok ($x,123456);
307 $z = $x->copy; $z++; ok ($z,123460);
308 $z = $x->copy(); $z->{_a} = 2; $z = $z / 2; ok ($z,62000);
310 $x = $mbi->new(123400); $x->{_a} = 4;
311 ok ($x->bnot(),-123400); # not -1234001
313 # both babs() and bneg() don't need to round, since the input will already
314 # be rounded (either as $x or via new($string)), and they don't change the
315 # value. The two tests below peek at this by using _a (illegally) directly
316 $x = $mbi->new(-123401); $x->{_a} = 4; ok ($x->babs(),123401);
317 $x = $mbi->new(-123401); $x->{_a} = 4; ok ($x->bneg(),123401);
319 # test fdiv rounding to A and R (bug in v1.48 and maybe earlier versions)
320 $mbf->round_mode('even');
321 $x = $mbf->new('740.7')->fdiv('6',4,undef,'zero'); ok ($x,'123.4');
323 $x = $mbi->new('123456'); $y = $mbi->new('123456'); $y->{_a} = 6;
324 ok ($x->bdiv($y),1); ok ($x->{_a},6); # carried over
326 $x = $mbi->new('123456'); $y = $mbi->new('123456'); $x->{_a} = 6;
327 ok ($x->bdiv($y),1); ok ($x->{_a},6); # carried over
329 $x = $mbi->new('123456'); $y = $mbi->new('223456'); $y->{_a} = 6;
330 ok ($x->bdiv($y),0); ok ($x->{_a},6); # carried over
332 $x = $mbi->new('123456'); $y = $mbi->new('223456'); $x->{_a} = 6;
333 ok ($x->bdiv($y),0); ok ($x->{_a},6); # carried over
335 ###############################################################################
336 # test that bop(0) does the same than bop(undef)
338 $x = $mbf->new('1234567890');
339 ok ($x->copy()->bsqrt(0),$x->copy()->bsqrt(undef));
340 ok ($x->copy->bsqrt(0),'35136.41828644462161665823116758077037159');
344 # test that bsqrt() modifies $x and does not just return something else
345 # (especially under BareCalc)
347 ok ($z,$x); ok ($x,'35136.41828644462161665823116758077037159');
349 $x = $mbf->new('1.234567890123456789');
350 ok ($x->copy()->bpow('0.5',0),$x->copy()->bpow('0.5',undef));
351 ok ($x->copy()->bpow('0.5',0),$x->copy()->bsqrt(undef));
352 ok ($x->copy()->bpow('2',0),'1.524157875323883675019051998750190521');
354 ###############################################################################
355 # test (also under Bare) that bfac() rounds at last step
357 ok ($mbi->new(12)->bfac(),'479001600');
358 ok ($mbi->new(12)->bfac(2),'480000000');
359 $x = $mbi->new(12); $x->accuracy(2); ok ($x->bfac(),'480000000');
360 $x = $mbi->new(13); $x->accuracy(2); ok ($x->bfac(),'6200000000');
361 $x = $mbi->new(13); $x->accuracy(3); ok ($x->bfac(),'6230000000');
362 $x = $mbi->new(13); $x->accuracy(4); ok ($x->bfac(),'6227000000');
363 # this does 1,2,3...9,10,11,12...20
364 $x = $mbi->new(20); $x->accuracy(1); ok ($x->bfac(),'2000000000000000000');
366 ###############################################################################
367 # test bsqrt) rounding to given A/P/R (bug prior to v1.60)
368 $x = $mbi->new('123456')->bsqrt(2,undef); ok ($x,'350'); # not 351
369 $x = $mbi->new('3')->bsqrt(2,undef); ok ($x->accuracy(),2);
371 $mbi->round_mode('even'); $x = $mbi->new('126025')->bsqrt(2,undef,'+inf');
372 ok ($x,'360'); # not 355 nor 350
374 $x = $mbi->new('126025')->bsqrt(undef,2); ok ($x,'400'); # not 355
377 ###############################################################################
378 # test mixed arguments
384 $z = $x + $y; ok ($z,12); ok (ref($z),$mbf);
385 $z = $x / $y; ok ($z,5); ok (ref($z),$mbf);
386 $z = $u * $y; ok ($z,5); ok (ref($z),$mbf);
388 $y = $mbi->new(12345);
389 $z = $u->copy()->bmul($y,2,undef,'odd'); ok ($z,31000);
390 $z = $u->copy()->bmul($y,3,undef,'odd'); ok ($z,30900);
391 $z = $u->copy()->bmul($y,undef,0,'odd'); ok ($z,30863);
392 $z = $u->copy()->bmul($y,undef,1,'odd'); ok ($z,30863);
393 $z = $u->copy()->bmul($y,undef,2,'odd'); ok ($z,30860);
394 $z = $u->copy()->bmul($y,undef,3,'odd'); ok ($z,30900);
395 $z = $u->copy()->bmul($y,undef,-1,'odd'); ok ($z,30862.5);
397 my $warn = ''; $SIG{__WARN__} = sub { $warn = shift; };
398 # these should warn, since '3.17' is a NaN in BigInt and thus >= returns undef
399 $warn = ''; eval "\$z = 3.17 <= \$y"; ok ($z, 1);
400 print "# Got: '$warn'\n" unless
401 ok ($warn =~ /^Use of uninitialized value (in numeric le \(<=\) |)at/);
402 $warn = ''; eval "\$z = \$y >= 3.17"; ok ($z, 1);
403 print "# Got: '$warn'\n" unless
404 ok ($warn =~ /^Use of uninitialized value (in numeric ge \(>=\) |)at/);
407 # $z = $y->copy()->bmul($u,2,0,'odd'); ok ($z,31000);
408 # $z = $y * $u; ok ($z,5); ok (ref($z),$mbi);
409 # $z = $y + $x; ok ($z,12); ok (ref($z),$mbi);
410 # $z = $y / $x; ok ($z,0); ok (ref($z),$mbi);
412 ###############################################################################
413 # rounding in bdiv with fallback and already set A or P
417 ${"$mbf\::accuracy"} = undef;
418 ${"$mbf\::precision"} = undef;
419 ${"$mbf\::div_scale"} = 40;
422 $x = $mbf->new(10); $x->{_a} = 4;
423 ok ($x->bdiv(3),'3.333');
424 ok ($x->{_a},4); # set's it since no fallback
426 $x = $mbf->new(10); $x->{_a} = 4; $y = $mbf->new(3);
427 ok ($x->bdiv($y),'3.333');
428 ok ($x->{_a},4); # set's it since no fallback
431 $x = $mbf->new(10); $x->{_p} = -2;
432 ok ($x->bdiv(3),'3.33');
434 # round in div with requested P
436 ok ($x->bdiv(3,undef,-2),'3.33');
438 # round in div with requested P greater than fallback
441 ${"$mbf\::div_scale"} = 5;
443 ok ($x->bdiv(3,undef,-8),'3.33333333');
444 ${"$mbf\::div_scale"} = 40;
447 $x = $mbf->new(10); $y = $mbf->new(3); $y->{_a} = 4;
448 ok ($x->bdiv($y),'3.333');
449 ok ($x->{_a},4); ok ($y->{_a},4); # set's it since no fallback
450 ok_undef ($x->{_p}); ok_undef ($y->{_p});
453 $x = $mbf->new(10); $y = $mbf->new(3); $y->{_p} = -2;
454 ok ($x->bdiv($y),'3.33');
457 ok_undef ($x->{_a}); ok_undef ($y->{_a});
459 ###############################################################################
460 # test whether bround(-n) fails in MBF (undocumented in MBI)
461 eval { $x = $mbf->new(1); $x->bround(-2); };
462 ok ($@ =~ /^bround\(\) needs positive accuracy/,1);
464 # test whether rounding to higher accuracy is no-op
465 $x = $mbf->new(1); $x->{_a} = 4;
467 $x->bround(6); # must be no-op
471 $x = $mbi->new(1230); $x->{_a} = 3;
473 $x->bround(6); # must be no-op
477 # bround(n) should set _a
478 $x->bround(2); # smaller works
482 # bround(-n) is undocumented and only used by MBF
483 # bround(-n) should set _a
484 $x = $mbi->new(12345);
489 # bround(-n) should set _a
490 $x = $mbi->new(12345);
495 # bround(-n) should set _a
496 $x = $mbi->new(12345); $x->{_a} = 5;
501 # bround(-n) should set _a
502 $x = $mbi->new(12345); $x->{_a} = 5;
507 # bround(-n) should be noop if n too big
508 $x = $mbi->new(12345);
510 ok ($x,'0'); # scale to "big" => 0
513 # bround(-n) should be noop if n too big
514 $x = $mbi->new(54321);
516 ok ($x,'100000'); # used by MBF to round 0.0054321 at 0.0_6_00000
519 # bround(-n) should be noop if n too big
520 $x = $mbi->new(54321); $x->{_a} = 5;
522 ok ($x,'100000'); # no-op
525 # bround(n) should set _a
526 $x = $mbi->new(12345); $x->{_a} = 5;
527 $x->bround(5); # must be no-op
531 # bround(n) should set _a
532 $x = $mbi->new(12345); $x->{_a} = 5;
533 $x->bround(6); # must be no-op
536 $x = $mbf->new('0.0061'); $x->bfround(-2); ok ($x,'0.01');
537 $x = $mbf->new('0.004'); $x->bfround(-2); ok ($x,'0.00');
538 $x = $mbf->new('0.005'); $x->bfround(-2); ok ($x,'0.00');
540 $x = $mbf->new('12345'); $x->bfround(2); ok ($x,'12340');
541 $x = $mbf->new('12340'); $x->bfround(2); ok ($x,'12340');
543 # MBI::bfround should clear A for negative P
544 $x = $mbi->new('1234'); $x->accuracy(3); $x->bfround(-2);
547 ###############################################################################
548 # rounding with already set precision/accuracy
550 $x = $mbf->new(1); $x->{_p} = -5;
553 # further rounding donw
554 ok ($x->bfround(-2),'1.00');
557 $x = $mbf->new(12345); $x->{_a} = 5;
558 ok ($x->bround(2),'12000');
561 $x = $mbf->new('1.2345'); $x->{_a} = 5;
562 ok ($x->bround(2),'1.2');
565 # mantissa/exponent format and A/P
566 $x = $mbf->new('12345.678'); $x->accuracy(4);
567 ok ($x,'12350'); ok ($x->{_a},4); ok_undef ($x->{_p});
568 ok_undef ($x->{_m}->{_a}); ok_undef ($x->{_e}->{_a});
569 ok_undef ($x->{_m}->{_p}); ok_undef ($x->{_e}->{_p});
571 # check for no A/P in case of fallback
573 $x = $mbf->new(100) / 3;
574 ok_undef ($x->{_a}); ok_undef ($x->{_p});
577 $x = $mbf->new(100) / 3; ($x,$y) = $x->bdiv(3);
578 ok_undef ($x->{_a}); ok_undef ($x->{_p});
579 ok_undef ($y->{_a}); ok_undef ($y->{_p});
581 ###############################################################################
582 # math with two numbers with differen A and P
584 $x = $mbf->new(12345); $x->accuracy(4); # '12340'
585 $y = $mbf->new(12345); $y->accuracy(2); # '12000'
586 ok ($x+$y,24000); # 12340+12000=> 24340 => 24000
588 $x = $mbf->new(54321); $x->accuracy(4); # '12340'
589 $y = $mbf->new(12345); $y->accuracy(3); # '12000'
590 ok ($x-$y,42000); # 54320+12300=> 42020 => 42000
592 $x = $mbf->new('1.2345'); $x->precision(-2); # '1.23'
593 $y = $mbf->new('1.2345'); $y->precision(-4); # '1.2345'
594 ok ($x+$y,'2.46'); # 1.2345+1.2300=> 2.4645 => 2.46
596 ###############################################################################
597 # round should find and use proper class
600 #ok ($x->round($Foo::accuracy),'a' x $Foo::accuracy);
601 #ok ($x->round(undef,$Foo::precision),'p' x $Foo::precision);
602 #ok ($x->bfround($Foo::precision),'p' x $Foo::precision);
603 #ok ($x->bround($Foo::accuracy),'a' x $Foo::accuracy);
605 ###############################################################################
606 # find out whether _find_round_parameters is doing what's it's supposed to do
610 ${"$mbi\::accuracy"} = undef;
611 ${"$mbi\::precision"} = undef;
612 ${"$mbi\::div_scale"} = 40;
613 ${"$mbi\::round_mode"} = 'odd';
617 my @params = $x->_find_round_parameters();
618 ok (scalar @params,1); # nothing to round
620 @params = $x->_find_round_parameters(1);
621 ok (scalar @params,4); # a=1
622 ok ($params[0],$x); # self
623 ok ($params[1],1); # a
624 ok_undef ($params[2]); # p
625 ok ($params[3],'odd'); # round_mode
627 @params = $x->_find_round_parameters(undef,2);
628 ok (scalar @params,4); # p=2
629 ok ($params[0],$x); # self
630 ok_undef ($params[1]); # a
631 ok ($params[2],2); # p
632 ok ($params[3],'odd'); # round_mode
634 eval { @params = $x->_find_round_parameters(undef,2,'foo'); };
635 ok ($@ =~ /^Unknown round mode 'foo'/,1);
637 @params = $x->_find_round_parameters(undef,2,'+inf');
638 ok (scalar @params,4); # p=2
639 ok ($params[0],$x); # self
640 ok_undef ($params[1]); # a
641 ok ($params[2],2); # p
642 ok ($params[3],'+inf'); # round_mode
644 @params = $x->_find_round_parameters(2,-2,'+inf');
645 ok (scalar @params,1); # error, A and P defined
646 ok ($params[0],$x); # self
650 ${"$mbi\::accuracy"} = 1;
651 @params = $x->_find_round_parameters(undef,-2);
652 ok (scalar @params,1); # error, A and P defined
653 ok ($params[0],$x); # self
654 ok ($x->is_nan(),1); # and must be NaN
656 ${"$mbi\::accuracy"} = undef;
657 ${"$mbi\::precision"} = 1;
658 @params = $x->_find_round_parameters(1,undef);
659 ok (scalar @params,1); # error, A and P defined
660 ok ($params[0],$x); # self
661 ok ($x->is_nan(),1); # and must be NaN
663 ${"$mbi\::precision"} = undef; # reset
666 ###############################################################################
667 # test whether bone/bzero take additional A & P, or reset it etc
669 foreach my $c ($mbi,$mbf)
671 $x = $c->new(2)->bzero(); ok_undef ($x->{_a}); ok_undef ($x->{_p});
672 $x = $c->new(2)->bone(); ok_undef ($x->{_a}); ok_undef ($x->{_p});
673 $x = $c->new(2)->binf(); ok_undef ($x->{_a}); ok_undef ($x->{_p});
674 $x = $c->new(2)->bnan(); ok_undef ($x->{_a}); ok_undef ($x->{_p});
676 $x = $c->new(2); $x->{_a} = 1; $x->{_p} = 2; $x->bnan();
677 ok_undef ($x->{_a}); ok_undef ($x->{_p});
678 $x = $c->new(2); $x->{_a} = 1; $x->{_p} = 2; $x->binf();
679 ok_undef ($x->{_a}); ok_undef ($x->{_p});
681 $x = $c->new(2,1); ok ($x->{_a},1); ok_undef ($x->{_p});
682 $x = $c->new(2,undef,1); ok_undef ($x->{_a}); ok ($x->{_p},1);
684 $x = $c->new(2,1)->bzero(); ok ($x->{_a},1); ok_undef ($x->{_p});
685 $x = $c->new(2,undef,1)->bzero(); ok_undef ($x->{_a}); ok ($x->{_p},1);
687 $x = $c->new(2,1)->bone(); ok ($x->{_a},1); ok_undef ($x->{_p});
688 $x = $c->new(2,undef,1)->bone(); ok_undef ($x->{_a}); ok ($x->{_p},1);
690 $x = $c->new(2); $x->bone('+',2,undef); ok ($x->{_a},2); ok_undef ($x->{_p});
691 $x = $c->new(2); $x->bone('+',undef,2); ok_undef ($x->{_a}); ok ($x->{_p},2);
692 $x = $c->new(2); $x->bone('-',2,undef); ok ($x->{_a},2); ok_undef ($x->{_p});
693 $x = $c->new(2); $x->bone('-',undef,2); ok_undef ($x->{_a}); ok ($x->{_p},2);
695 $x = $c->new(2); $x->bzero(2,undef); ok ($x->{_a},2); ok_undef ($x->{_p});
696 $x = $c->new(2); $x->bzero(undef,2); ok_undef ($x->{_a}); ok ($x->{_p},2);
699 ###############################################################################
700 # test whether bone/bzero honour globals
702 for my $c ($mbi,$mbf)
705 $x = $c->bone(); ok ($x->accuracy(),2);
706 $x = $c->bzero(); ok ($x->accuracy(),2);
710 $x = $c->bone(); ok ($x->precision(),-2);
711 $x = $c->bzero(); ok ($x->precision(),-2);
712 $c->precision(undef);
715 ###############################################################################
716 # check whether mixing A and P creates a NaN
718 # new with set accuracy/precision and with parameters
721 foreach my $c ($mbi,$mbf)
723 ok ($c->new(123,4,-3),'NaN'); # with parameters
724 ${"$c\::accuracy"} = 42;
725 ${"$c\::precision"} = 2;
726 ok ($c->new(123),'NaN'); # with globals
727 ${"$c\::accuracy"} = undef;
728 ${"$c\::precision"} = undef;
733 foreach my $class ($mbi,$mbf)
735 foreach (qw/add sub mul pow mod/)
736 #foreach (qw/add sub mul div pow mod/)
738 my $try = "my \$x = $class->new(1234); \$x->accuracy(5); ";
739 $try .= "my \$y = $class->new(12); \$y->precision(-3); ";
740 $try .= "\$x->b$_(\$y);";
742 print "# Tried: '$try'\n" if !ok ($rc, 'NaN');
747 foreach (qw/new bsqrt/)
749 my $try = 'my $x = $mbi->$_(1234,5,-3); ';
751 print "# Tried: '$try'\n" if !ok ($rc, 'NaN');
754 # see if $x->bsub(0) and $x->badd(0) really round
755 foreach my $class ($mbi,$mbf)
757 $x = $class->new(123); $class->accuracy(2); $x->bsub(0);
759 $class->accuracy(undef);
760 $x = $class->new(123); $class->accuracy(2); $x->badd(0);
762 $class->accuracy(undef);
765 ###############################################################################
766 # test whether shortcuts returning zero/one preserve A and P
768 my ($ans1,$f,$a,$p,$xp,$yp,$xa,$ya,$try,$ans,@args);
769 my $CALC = Math::BigInt->config()->{lib};
773 next if /^\s*(#|$)/; # skip comments and empty lines
776 $f = $_; next; # function
778 @args = split(/:/,$_,99);
779 my $ans = pop(@args);
781 ($x,$xa,$xp) = split (/,/,$args[0]);
782 $xa = $xa || ''; $xp = $xp || '';
783 $try = "\$x = $mbi->new('$x'); ";
784 $try .= "\$x->accuracy($xa); " if $xa ne '';
785 $try .= "\$x->precision($xp); " if $xp ne '';
787 ($y,$ya,$yp) = split (/,/,$args[1]);
788 $ya = $ya || ''; $yp = $yp || '';
789 $try .= "\$y = $mbi->new('$y'); ";
790 $try .= "\$y->accuracy($ya); " if $ya ne '';
791 $try .= "\$y->precision($yp); " if $yp ne '';
793 $try .= "\$x->$f(\$y);";
795 # print "trying $try\n";
797 # convert hex/binary targets to decimal
798 if ($ans =~ /^(0x0x|0b0b)/)
801 $ans = $mbi->new($ans)->bstr();
803 print "# Tried: '$try'\n" if !ok ($rc, $ans);
804 # check internal state of number objects
805 is_valid($rc,$f) if ref $rc;
807 # now check whether A and P are set correctly
808 # only one of $a or $p will be set (no crossing here)
809 $a = $xa || $ya; $p = $xp || $yp;
811 # print "Check a=$a p=$p\n";
812 # print "# Tried: '$try'\n";
815 if (!(ok ($x->{_a}, $a) && ok_undef ($x->{_p})))
817 print "# Check: A=$a and P=undef\n";
818 print "# Tried: '$try'\n";
823 if (!(ok ($x->{_p}, $p) && ok_undef ($x->{_a})))
825 print "# Check: A=undef and P=$p\n";
826 print "# Tried: '$try'\n";
834 ###############################################################################
835 ###############################################################################
836 # Perl 5.005 does not like ok ($x,undef)
842 ok (1,1) and return 1 if !defined $x;
844 print "# Called from ",join(' ',caller()),"\n";
848 ###############################################################################
849 # sub to check validity of a BigInt internally, to ensure that no op leaves a
850 # number object in an invalid state (f.i. "-0")
858 $e = 'Not a reference' if !ref($x);
861 $e = "Illegal sign $x->{sign} (expected: '+', '-', '-inf', '+inf' or 'NaN'"
862 if $e eq '0' && $x->{sign} !~ /^(\+|-|\+inf|-inf|NaN)$/;
864 $e = "-0 is invalid!" if $e ne '0' && $x->{sign} eq '-' && $x == 0;
865 $e = $CALC->_check($x->{value}) if $e eq '0';
867 # test done, see if error did crop up
868 ok (1,1), return if ($e eq '0');
870 ok (1,$e." after op '$f'");
875 # 123,,3 means 123 with precision 3 (A is undef)
876 # the A or P of the result is calculated automatically
931 # 250 ^ 4095 = 3845 => 3800
933 # 255 ^ 4100 = 4347 => 4300
936 # 255 ^ 4100 = 10fb => 4347 => 4300
945 # FF | FA = FF => 250