diff options
author | Tels <nospam-abuse@bloodgate.com> | 2005-02-09 22:44:22 +0100 |
---|---|---|
committer | Rafael Garcia-Suarez <rgarciasuarez@gmail.com> | 2005-02-10 10:51:59 +0000 |
commit | 32db35a5d266747d1db7d569786dd59956d078cc (patch) | |
tree | 59c9b97c26851f5b8cae4779eb9b726f64f233d0 | |
parent | 8bcf31409331fe2aaa2c5d72d8f98a9a33554f66 (diff) | |
download | perl-32db35a5d266747d1db7d569786dd59956d078cc.tar.gz |
Re: [PATCH] BigInt mbi_rand.t failings (solved now)
Message-Id: <200502092144.24051@bloodgate.com>
p4raw-id: //depot/perl@23955
-rw-r--r-- | lib/Math/BigInt/Calc.pm | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/lib/Math/BigInt/Calc.pm b/lib/Math/BigInt/Calc.pm index 2fafc51c83..39a0435746 100644 --- a/lib/Math/BigInt/Calc.pm +++ b/lib/Math/BigInt/Calc.pm @@ -581,8 +581,22 @@ sub _div_use_mul # fit's into one Perl scalar, so result can be computed directly # cannot use int() here, because it rounds wrongly on some systems #$x->[0] = int($x->[-1] / $yorg->[-1]); - # round to 8 digits, then truncate result to integer - $x->[0] = int ( sprintf ("%.8f", $x->[-1] / $yorg->[-1]) ); + + # Due to chopping up the number into parts, the two first parts + # may have only one or two digits. So we use more from the second + # parts (it always has at least two parts) for more accuracy: + # Round to 8 digits, then truncate result to integer: + my $x0 = $x->[-1]; + my $y0 = $yorg->[-1]; + if (length ($x0) < $BASE_LEN) # len($x0) == len($y0)! + { + $x0 .= substr('0' x $BASE_LEN . $x->[-2], -$BASE_LEN, $BASE_LEN); + $x0 = substr($x0,0,$BASE_LEN); + $y0 .= substr('0' x $BASE_LEN . $yorg->[-2], -$BASE_LEN, $BASE_LEN); + $y0 = substr($y0,0,$BASE_LEN); + } + $x->[0] = int ( sprintf ("%.8f", $x0 / $y0 ) ); + splice(@$x,1); # keep single element return $x; } @@ -782,8 +796,22 @@ sub _div_use_div # fit's into one Perl scalar, so result can be computed directly # cannot use int() here, because it rounds wrongly on some systems #$x->[0] = int($x->[-1] / $yorg->[-1]); - # round to 8 digits, then truncate result to integer - $x->[0] = int ( sprintf ("%.8f", $x->[-1] / $yorg->[-1]) ); + + # Due to chopping up the number into parts, the two first parts + # may have only one or two digits. So we use more from the second + # parts (it always has at least two parts) for more accuracy: + # Round to 8 digits, then truncate result to integer: + my $x0 = $x->[-1]; + my $y0 = $yorg->[-1]; + if (length ($x0) < $BASE_LEN) # len($x0) == len($y0)! + { + $x0 .= substr('0' x $BASE_LEN . $x->[-2], -$BASE_LEN, $BASE_LEN); + $x0 = substr($x0,0,$BASE_LEN); + $y0 .= substr('0' x $BASE_LEN . $yorg->[-2], -$BASE_LEN, $BASE_LEN); + $y0 = substr($y0,0,$BASE_LEN); + } + $x->[0] = int ( sprintf ("%.8f", $x0 / $y0 ) ); + splice(@$x,1); # keep single element return $x; } @@ -958,7 +986,7 @@ sub _digit my $elem = int($n / $BASE_LEN); # which array element my $digit = $n % $BASE_LEN; # which digit in this element - $elem = '0000000'.@$x[$elem]; # get element padded with 0's + $elem = '0' x $BASE_LEN . @$x[$elem]; # get element padded with 0's substr($elem,-$digit-1,1); } |