# _a : accuracy
# _p : precision
-$VERSION = '1.48';
+$VERSION = '1.49';
require 5.005;
require Exporter;
$scale = $ly if $ly > $scale;
my $diff = $ly - $lx;
$scale += $diff if $diff > 0; # if lx << ly, but not if ly << lx!
-
- # cases like $x /= $x (but not $x /= $y!) were wrong due to modifying $x
- # twice below)
- require Scalar::Util;
- if (Scalar::Util::refaddr($x) == Scalar::Util::refaddr($y))
+
+ # already handled inf/NaN/-inf above:
+
+ my $xsign = $x->{sign};
+ $y->{sign} =~ tr/+-/-+/;
+ my $y_not_one = !$y->is_one(); # cache this result
+ if ($xsign ne $x->{sign})
{
- $x->bone(); # x/x => 1, rem 0
+ # special case of $x /= $x results in 1
+ $x->bone();
}
else
{
-
+ # correct $y's sign again
+ $y->{sign} =~ tr/+-/-+/;
+ # continue with normal div code:
+
# make copy of $x in case of list context for later reminder calculation
- if (wantarray && !$y->is_one())
+ if (wantarray && $y_not_one)
{
$rem = $x->copy();
}
$x->{sign} = $x->{sign} ne $y->sign() ? '-' : '+';
# check for / +-1 ( +/- 1E0)
- if (!$y->is_one())
+ if ($y_not_one)
{
# promote BigInts and it's subclasses (except when already a BigFloat)
$y = $self->new($y) unless $y->isa('Math::BigFloat');
if (wantarray)
{
- if (!$y->is_one())
+ if ($y_not_one)
{
$rem->bmod($y,@params); # copy already done
}
supplied to the operation after the I<scale>:
$x = Math::BigFloat->new(2);
- Math::BigFloat->precision(5); # 5 digits max
- $y = $x->copy()->bdiv(3); # will give 0.66666
- $y = $x->copy()->bdiv(3,6); # will give 0.666666
- $y = $x->copy()->bdiv(3,6,'odd'); # will give 0.666667
+ Math::BigFloat->accuracy(5); # 5 digits max
+ $y = $x->copy()->bdiv(3); # will give 0.66667
+ $y = $x->copy()->bdiv(3,6); # will give 0.666667
+ $y = $x->copy()->bdiv(3,6,undef,'odd'); # will give 0.666667
Math::BigFloat->round_mode('zero');
- $y = $x->copy()->bdiv(3,6); # will give 0.666666
+ $y = $x->copy()->bdiv(3,6); # will also give 0.666667
+
+Note that C<< Math::BigFloat->accuracy() >> and C<< Math::BigFloat->precision() >>
+set the global variables, and thus B<any> newly created number will be subject
+to the global rounding. This means that in the examples above, the C<3>
+as argument to C<bdiv()> 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
+functions like so:
+
+ use Math::BigFloat;
+ $x = Math::BigFloat->new(2);
+ $y = $x->copy()->bdiv(3);
+ print $y->bround(5),"\n"; # will give 0.66667
+
+ or
+
+ use Math::BigFloat;
+ $x = Math::BigFloat->new(2);
+ $y = $x->copy()->bdiv(3,5); # will give 0.66667
+ print "$y\n";
=head2 Rounding
my $class = "Math::BigInt";
require 5.005;
-$VERSION = '1.74';
+$VERSION = '1.75';
@ISA = qw( Exporter );
@EXPORT_OK = qw( objectify bgcd blcm);
'cos' => sub { cos($_[0]->numify()) },
'sin' => sub { sin($_[0]->numify()) },
'exp' => sub { exp($_[0]->numify()) },
-'atan2' => sub { atan2($_[0]->numify(),$_[1]) },
+'atan2' => sub { $_[2] ?
+ atan2($_[1],$_[0]->numify()) :
+ atan2($_[0]->numify(),$_[1]) },
# are not yet overloadable
#'hex' => sub { print "hex"; $_[0]; },
# for subtract it's a bit tricky to not modify b: b-a => -a+b
'-' => sub { my $c = $_[0]->copy; $_[2] ?
- $c->bneg()->badd( $_[1]) :
- $c->bsub( $_[1]) },
+ $c->bneg()->badd( $_[1]) :
+ $c->bsub( $_[1]) },
'+' => sub { $_[0]->copy()->badd($_[1]); },
'*' => sub { $_[0]->copy()->bmul($_[1]); },
return $x->round(@r) if $y->is_zero();
- require Scalar::Util;
- if (Scalar::Util::refaddr($x) == Scalar::Util::refaddr($y))
+ # To correctly handle the lone special case $x->bsub($x), we note the sign
+ # of $x, then flip the sign from $y, and if the sign of $x did change, too,
+ # then we caught the special case:
+ my $xsign = $x->{sign};
+ $y->{sign} =~ tr/+\-/-+/; # does nothing for NaN
+ if ($xsign ne $x->{sign})
{
- # if we get the same variable twice, the result must be zero (the code
- # below fails in that case)
- return $x->bzero(@r) if $x->{sign} =~ /^[+-]$/;
+ # special case of $x->bsub($x) results in 0
+ return $x->bzero(@r) if $xsign =~ /^[+-]$/;
return $x->bnan(); # NaN, -inf, +inf
}
- $y->{sign} =~ tr/+\-/-+/; # does nothing for NaN
$x->badd($y,@r); # badd does not leave internal zeros
$y->{sign} =~ tr/+\-/-+/; # refix $y (does nothing for NaN)
$x; # already rounded by badd() or no round necc.
{
if (($WARN{$lib}||0) < 2)
{
- my $ver = eval "\$$lib\::VERSION";
+ my $ver = eval "\$$lib\::VERSION" || 'unknown';
require Carp;
Carp::carp ("Cannot load outdated $lib v$ver, please upgrade");
$WARN{$lib} = 2; # never warn again
# automatically at loading time to be the maximum possible value
# todo:
-# - fully remove funky $# stuff (maybe)
+# - fully remove funky $# stuff in div() (maybe - that code scares me...)
# USE_MUL: due to problems on certain os (os390, posix-bc) "* 1e-5" is used
# instead of "/ 1e5" at some places, (marked with USE_MUL). Other platforms
}
print "# INC = @INC\n";
- plan tests => 3012;
+ plan tests => 3014;
}
use Math::BigInt lib => 'BareCalc';
9999999_9999999_9999999_9999999:100_0000000_0000000_0000000:99999
9999999_9999999_9999999_9999999:10_0000000_0000000_0000000:999999
9999999_9999999_9999999_9999999:1_0000000_0000000_0000000:9999999
+# bug with shortcut in Calc 0.44
+949418181818187070707070707070707070:181818181853535353535353535353535353:5
&bmodinv
# format: number:modulus:result
# bmodinv Data errors
my $location = $0; $location =~ s/bigintpm.t//;
unshift @INC, $location; # to locate the testing files
chdir 't' if -d 't';
- plan tests => 3012;
+ plan tests => 3014;
}
use Math::BigInt;
}
print "# INC = @INC\n";
- plan tests => 8;
+ plan tests => 12;
}
# The tests below test that cos(BigInt) = cos(Scalar) which is DWIM, but not
-# exactly right, ideally cos(BigInt) should truncate to int() and cos(BigFLoat)
+# exactly right, ideally cos(BigInt) should truncate to int() and cos(BigFloat)
# should calculate the result to X digits accuracy. For now, this is better
# than die()ing...
ok (exp($bi), exp(1));
ok (atan2($bi,$bi), atan2(1,1));
-my $bf = Math::BigInt->new(1);
+my $bf = Math::BigInt->new(0);
-ok (cos($bf), cos(1));
-ok (sin($bf), sin(1));
-ok (exp($bf), exp(1));
-ok (atan2($bf,$bf), atan2(1,1));
+ok (cos($bf), cos(0));
+ok (sin($bf), sin(0));
+ok (exp($bf), exp(0));
+ok (atan2($bi,$bf), atan2(1,0));
+ok (atan2($bf,$bi), atan2(0,1));
+
+my $bone = Math::BigInt->new(1);
+ok (cos($bone), cos(1));
+ok (sin($bone), sin(1));
+ok (exp($bone), exp(1));
my $seed = ($#ARGV == 0) ? $ARGV[0] : int(rand(1165537));
print "# seed: $seed\n"; srand($seed);
+print "# lib: ", Math::BigInt->config()->{lib},"\n";
+if (Math::BigInt->config()->{lib} =~ /::Calc/)
+ {
+ print "# base len: ", scalar Math::BigInt::Calc->_base_len(),"\n";
+ }
+
my ($A,$B,$As,$Bs,$ADB,$AMB,$la,$lb);
my $two = Math::BigInt->new(2);
for (my $i = 0; $i < $count; $i++)
$As =~ s/^0+//; $Bs =~ s/^0+//;
$As = $As || '0'; $Bs = $Bs || '0';
- # print "# As $As\n# Bs $Bs\n";
+# print "# As $As\n# Bs $Bs\n";
$A = $c->new($As); $B = $c->new($Bs);
- # print "# A $A\n# B $B\n";
+ print "# A $A\n# B $B\n";
if ($A->is_zero() || $B->is_zero())
{
for (1..4) { ok (1,1); } next;
# $X = ($A/$B)*$B + 2 * ($A % $B) - ($A % $B);
($ADB,$AMB) = $A->copy()->bdiv($B);
-# print "# ($A / $B, $A % $B ) = $ADB $AMB\n";
+ print "# ($A / $B, $A % $B ) = $ADB $AMB\n";
print "# seed $seed, ". join(' ',Math::BigInt::Calc->_base_len()),"\n".
"# tried $ADB * $B + $two*$AMB - $AMB\n"
unless ok ($ADB*$B+$two*$AMB-$AMB,$As);
- print "# seed: $seed, \$ADB * \$B / \$B = ", $ADB * $B / $B, " != $ADB (\$B=$B)\n"
- unless ok ($ADB*$B/$B,$ADB);
+ if (ok ($ADB*$B/$B,$ADB))
+ {
+ print "# seed: $seed, \$ADB * \$B / \$B = ", $ADB * $B / $B, " != $ADB (\$B=$B)\n";
+ if (Math::BigInt->config()->{lib} =~ /::Calc/)
+ {
+ print "# ADB->[-1]: ", $ADB->{value}->[-1], " B->[-1]: ", $B->{value}->[-1],"\n";
+ }
+ }
# swap 'em and try this, too
# $X = ($B/$A)*$A + $B % $A;
($ADB,$AMB) = $B->copy()->bdiv($A);
- #print "check: $ADB $AMB";
+ # print "check: $ADB $AMB";
print "# seed $seed, ". join(' ',Math::BigInt::Calc->_base_len()),"\n".
"# tried $ADB * $A + $two*$AMB - $AMB\n"
unless ok ($ADB*$A+$two*$AMB-$AMB,$Bs);
-# print " +$two * $AMB = ",$ADB * $A + $two * $AMB,"\n";
-# print " -$AMB = ",$ADB * $A + $two * $AMB - $AMB,"\n";
+ print "# +$two * $AMB = ",$ADB * $A + $two * $AMB,"\n";
+ print "# -$AMB = ",$ADB * $A + $two * $AMB - $AMB,"\n";
print "# seed $seed, \$ADB * \$A / \$A = ", $ADB * $A / $A, " != $ADB (\$A=$A)\n"
unless ok ($ADB*$A/$A,$ADB);
}
}
print "# INC = @INC\n";
- plan tests => 3012
+ plan tests => 3014
+ 5; # +5 own tests
}