#!perl # test inf/NaN handling all in one place # Thanx to Jarkko for the excellent explanations and the tables use strict; use warnings; use lib 't'; use Test::More tests => 2052; use Math::BigInt; use Math::BigFloat; use Math::BigInt::Subclass; use Math::BigFloat::Subclass; my @biclasses = qw/ Math::BigInt Math::BigInt::Subclass /; my @bfclasses = qw/ Math::BigFloat Math::BigFloat::Subclass /; my (@args, $x, $y, $z); # + foreach (qw/ -inf:-inf:-inf -1:-inf:-inf -0:-inf:-inf 0:-inf:-inf 1:-inf:-inf inf:-inf:NaN NaN:-inf:NaN -inf:-1:-inf -1:-1:-2 -0:-1:-1 0:-1:-1 1:-1:0 inf:-1:inf NaN:-1:NaN -inf:0:-inf -1:0:-1 -0:0:0 0:0:0 1:0:1 inf:0:inf NaN:0:NaN -inf:1:-inf -1:1:0 -0:1:1 0:1:1 1:1:2 inf:1:inf NaN:1:NaN -inf:inf:NaN -1:inf:inf -0:inf:inf 0:inf:inf 1:inf:inf inf:inf:inf NaN:inf:NaN -inf:NaN:NaN -1:NaN:NaN -0:NaN:NaN 0:NaN:NaN 1:NaN:NaN inf:NaN:NaN NaN:NaN:NaN /) { @args = split /:/, $_; for my $class (@biclasses, @bfclasses) { $x = $class->new($args[0]); $y = $class->new($args[1]); $args[2] = '0' if $args[2] eq '-0'; # Math::Big(Int|Float) has no -0 my $r = $x->badd($y); is($x->bstr(), $args[2], "x $class $args[0] + $args[1]"); is($x->bstr(), $args[2], "r $class $args[0] + $args[1]"); } } # - foreach (qw/ -inf:-inf:NaN -1:-inf:inf -0:-inf:inf 0:-inf:inf 1:-inf:inf inf:-inf:inf NaN:-inf:NaN -inf:-1:-inf -1:-1:0 -0:-1:1 0:-1:1 1:-1:2 inf:-1:inf NaN:-1:NaN -inf:0:-inf -1:0:-1 -0:0:-0 0:0:0 1:0:1 inf:0:inf NaN:0:NaN -inf:1:-inf -1:1:-2 -0:1:-1 0:1:-1 1:1:0 inf:1:inf NaN:1:NaN -inf:inf:-inf -1:inf:-inf -0:inf:-inf 0:inf:-inf 1:inf:-inf inf:inf:NaN NaN:inf:NaN -inf:NaN:NaN -1:NaN:NaN -0:NaN:NaN 0:NaN:NaN 1:NaN:NaN inf:NaN:NaN NaN:NaN:NaN /) { @args = split /:/, $_; for my $class (@biclasses, @bfclasses) { $x = $class->new($args[0]); $y = $class->new($args[1]); $args[2] = '0' if $args[2] eq '-0'; # Math::Big(Int|Float) has no -0 my $r = $x->bsub($y); is($x->bstr(), $args[2], "x $class $args[0] - $args[1]"); is($r->bstr(), $args[2], "r $class $args[0] - $args[1]"); } } # * foreach (qw/ -inf:-inf:inf -1:-inf:inf -0:-inf:NaN 0:-inf:NaN 1:-inf:-inf inf:-inf:-inf NaN:-inf:NaN -inf:-1:inf -1:-1:1 -0:-1:0 0:-1:-0 1:-1:-1 inf:-1:-inf NaN:-1:NaN -inf:0:NaN -1:0:-0 -0:0:-0 0:0:0 1:0:0 inf:0:NaN NaN:0:NaN -inf:1:-inf -1:1:-1 -0:1:-0 0:1:0 1:1:1 inf:1:inf NaN:1:NaN -inf:inf:-inf -1:inf:-inf -0:inf:NaN 0:inf:NaN 1:inf:inf inf:inf:inf NaN:inf:NaN -inf:NaN:NaN -1:NaN:NaN -0:NaN:NaN 0:NaN:NaN 1:NaN:NaN inf:NaN:NaN NaN:NaN:NaN /) { @args = split /:/, $_; for my $class (@biclasses, @bfclasses) { $x = $class->new($args[0]); $y = $class->new($args[1]); $args[2] = '0' if $args[2] eq '-0'; # Math::Big(Int|Float) has no -0 my $r = $x->bmul($y); is($x->bstr(), $args[2], "x $class $args[0] * $args[1]"); is($r->bstr(), $args[2], "r $class $args[0] * $args[1]"); } } # / foreach (qw/ -inf:-inf:NaN -1:-inf:0 -0:-inf:0 0:-inf:-0 1:-inf:-1 inf:-inf:NaN NaN:-inf:NaN -inf:-1:inf -1:-1:1 -0:-1:0 0:-1:-0 1:-1:-1 inf:-1:-inf NaN:-1:NaN -inf:0:-inf -1:0:-inf -0:0:NaN 0:0:NaN 1:0:inf inf:0:inf NaN:0:NaN -inf:1:-inf -1:1:-1 -0:1:-0 0:1:0 1:1:1 inf:1:inf NaN:1:NaN -inf:inf:NaN -1:inf:-1 -0:inf:-0 0:inf:0 1:inf:0 inf:inf:NaN NaN:inf:NaN -inf:NaN:NaN -1:NaN:NaN -0:NaN:NaN 0:NaN:NaN 1:NaN:NaN inf:NaN:NaN NaN:NaN:NaN /) { @args = split /:/, $_; for my $class (@biclasses, @bfclasses) { $x = $class->new($args[0]); $y = $class->new($args[1]); $args[2] = '0' if $args[2] eq '-0'; # Math::Big(Int|Float) has no -0 my $t = $x->copy(); my $tmod = $t->copy(); # bdiv in scalar context unless ($class =~ /^Math::BigFloat/) { my $r = $x->bdiv($y); is($x->bstr(), $args[2], "x $class $args[0] / $args[1]"); is($r->bstr(), $args[2], "r $class $args[0] / $args[1]"); } # bmod and bdiv in list context my ($d, $rem) = $t->bdiv($y); # bdiv in list context is($t->bstr(), $args[2], "t $class $args[0] / $args[1]"); is($d->bstr(), $args[2], "d $class $args[0] / $args[1]"); # bmod my $m = $tmod->bmod($y); # bmod() agrees with bdiv? is($m->bstr(), $rem->bstr(), "m $class $args[0] % $args[1]"); # bmod() return agrees with set value? is($tmod->bstr(), $m->bstr(), "o $class $args[0] % $args[1]"); } } # / foreach (qw/ -inf:-inf:NaN -1:-inf:0 -0:-inf:0 0:-inf:-0 1:-inf:-0 inf:-inf:NaN NaN:-inf:NaN -inf:-1:inf -1:-1:1 -0:-1:0 0:-1:-0 1:-1:-1 inf:-1:-inf NaN:-1:NaN -inf:0:-inf -1:0:-inf -0:0:NaN 0:0:NaN 1:0:inf inf:0:inf NaN:0:NaN -inf:1:-inf -1:1:-1 -0:1:-0 0:1:0 1:1:1 inf:1:inf NaN:1:NaN -inf:inf:NaN -1:inf:-0 -0:inf:-0 0:inf:0 1:inf:0 inf:inf:NaN NaN:inf:NaN -inf:NaN:NaN -1:NaN:NaN -0:NaN:NaN 0:NaN:NaN 1:NaN:NaN inf:NaN:NaN NaN:NaN:NaN /) { @args = split /:/, $_; for my $class (@bfclasses) { $x = $class->new($args[0]); $y = $class->new($args[1]); $args[2] = '0' if $args[2] eq '-0'; # Math::Big(Int|Float) has no -0 my $t = $x->copy(); my $tmod = $t->copy(); # bdiv in scalar context my $r = $x->bdiv($y); is($x->bstr(), $args[2], "x $class $args[0] / $args[1]"); is($r->bstr(), $args[2], "r $class $args[0] / $args[1]"); } } ############################################################################# # overloaded comparisons foreach my $c (@biclasses, @bfclasses) { my $x = $c->bnan(); my $y = $c->bnan(); # test with two different objects, too my $z = $c->bzero(); is($x == $y, '', 'NaN == NaN: ""'); is($x != $y, 1, 'NaN != NaN: 1'); is($x == $x, '', 'NaN == NaN: ""'); is($x != $x, 1, 'NaN != NaN: 1'); is($z != $x, 1, '0 != NaN: 1'); is($z == $x, '', '0 == NaN: ""'); is($z < $x, '', '0 < NaN: ""'); is($z <= $x, '', '0 <= NaN: ""'); is($z >= $x, '', '0 >= NaN: ""'); #is($z > $x, '', '0 > NaN: ""'); # Bug! Todo: fix it! } # All done.