0

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
  • Edit your question, and include some code, please. Also, are you using bcpow() to get those small floats, or are you using floating-point exponentiation? Or something else? – Mike Sherrill 'Cat Recall' Jan 31 '13 at 02:39
  • [What Every Programmer Should Know About Floating-Point Arithmetic or Why don’t my numbers add up?](http://floating-point-gui.de/) –  Jan 31 '13 at 02:54
  • @Dagon: php's bc*() functions aren't floating-point functions. They're functions that operate on arbitrary-precision numbers. – Mike Sherrill 'Cat Recall' Jan 31 '13 at 03:05

1 Answers1

3

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.

Mike Sherrill 'Cat Recall'
  • 91,602
  • 17
  • 122
  • 185
  • 1
    Yes, it will take a lot longer than comparable floating-point arithmetic. But floating-point arithmetic returns the wrong answer, doesn't it? You can cast or convert values to strings in various ways, but php will generally do implicit conversions for you. (See code and comments above.) The critical thing is to avoid floating-point expressions when you're doing arbitrary-precision arithmetic. – Mike Sherrill 'Cat Recall' Jan 31 '13 at 03:47