Question

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
Was it helpful?

Solution

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\n", $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\n", $q_2);

printf("sum: %s\n", 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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top