From 52edfb599e340320dace5311afb7593b66043d71 Mon Sep 17 00:00:00 2001 From: Tels Date: Wed, 9 Feb 2005 22:44:22 +0100 Subject: [PATCH] Re: [PATCH] BigInt mbi_rand.t failings (solved now) Message-Id: <200502092144.24051@bloodgate.com> p4raw-id: //depot/perl@23955 --- lib/Math/BigInt/Calc.pm | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/lib/Math/BigInt/Calc.pm b/lib/Math/BigInt/Calc.pm index 2fafc51..39a0435 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); } -- 2.7.4