summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTels <nospam-abuse@bloodgate.com>2005-02-09 22:44:22 +0100
committerRafael Garcia-Suarez <rgarciasuarez@gmail.com>2005-02-10 10:51:59 +0000
commit32db35a5d266747d1db7d569786dd59956d078cc (patch)
tree59c9b97c26851f5b8cae4779eb9b726f64f233d0
parent8bcf31409331fe2aaa2c5d72d8f98a9a33554f66 (diff)
downloadperl-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.pm38
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);
}