Thanks to stack, I learned about floating point imprecision, so I went over to the bc functions.
That works great on "normal" floats, but with extremely small floats, say 10^-10
types, bcadd
always gives 0
.
Can someone show me what I'm doing wrong to make these small floats add with precision?
Many thanks in advance!
PHP
$numerator = 1;
$denominator = 1000000000;
$quotientOne = $numerator / $denominator;
$numerator = 1;
$denominator = 1000000000000000;
$quotientTwo = $numerator / $denominator;
$smallSum = bcadd($quotientOne, $quotientTwo, 100);
echo $quotientOne . "<br>";
echo $quotientTwo . "<br>";
echo $smallSum . "<br>";
gives
1.0E-9
1.0E-15
0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
The /
operator returns either a float or an integer. It's interfering with your attempts to use bcadd() correctly. The limitations of floating-point arithmetic will take hold before bcadd() gets a chance to show its stuff.
echo gettype($numerator / $denominator);
double
Use bcdiv()
instead. Note that the bc*() functions take strings as their arguments, and they also return a string.
$ cat code/php/test.php
<?php
$num_1 = 1;
$denom_1 = 1000000000;
# Cast values to string type to be crystal clear about what you're doing.
$q_1 = bcdiv((string)$num_1, (string)$denom_1, strlen($denom_1));
printf("q_1: %s
", $q_1);
$num_2 = 1;
$denom_2 = 1000000000000000;
# php will do an implicit conversion to string anyway, though.
$q_2 = bcdiv($num_2, $denom_2, strlen($denom_2));
printf("q_2: %s
", $q_2);
printf("sum: %s
", bcadd($q_1, $q_2, strlen($denom_2)));
?>
$ php code/php/test.php
q_1: 0.0000000010
q_2: 0.0000000000000010
sum: 0.0000000010000010
Arbitrary-precision arithmetic is inherently slower than floating-point arithmetic. That's the price you pay for dozens, hundreds, or thousands of digits of accuracy.