Question

I still can't get accurate results. What is the max. amount of decimals I should display if I want it to be as accurate as possible?

Some code (ready to be copy-pasted and tested):

// Test with 5 decimals 
$a = 0.00001;
echo bcadd($a,$a,5) . '<br/>';
echo bcadd($a,$a,6) . '<br/>';
echo number_format(bcadd($a,$a,5),5) . '<br/>';
echo number_format(bcadd($a,$a,5),6) . '<br/>';
echo bcadd(0.00001,0.00001,20) . '<br/>';
echo number_format(bcadd($a,$a,20),5) . '<br/>';
echo number_format(bcadd($a,$a,20),21) . '<br/><br/>';

/* Output:
0.00000
0.000000
0.00000
0.000000
0.00000000000000000000
0.00000
0.000000000000000000000
*/

// Test with 4 decimals
$a = 0.0001;
echo bcadd($a,$a,5) . '<br/>';
echo bcadd($a,$a,6) . '<br/>';
echo number_format(bcadd($a,$a,5),5) . '<br/>';
echo number_format(bcadd($a,$a,5),6) . '<br/>';
echo bcadd(0.00001,0.00001,20) . '<br/>'; // wtf? this outputs 0 too?
echo number_format(bcadd($a,$a,20),5) . '<br/>';
echo number_format(bcadd($a,$a,20),21) . '<br/>';

/* Output:
0.00020
0.000200
0.00020
0.000200
0.00000000000000000000
0.00020
0.000200000000000000010
*/

Should I infer that the answer is 4 ??? But I still have a problem in the line with a comment

Edit: I don't think anyone understood my tests. I know floats are inaccurate. But one thing is 1 != 0.98990123, and other thing is 1 != 0.0000. If I set 4 as the precision in the bc* function, I expect to get at least 0.9899 (if the perfect answer were 1), not 0.0000. One thing is 'not perfectly accurate for infinite precision', other thing is 'completely useless'.

Edit 2: @Michael Borgwardt has the solution

Was it helpful?

Solution

A major cause of your problem is that you're using float literals. That causes a rounding error when the code is compiled or interpreted and converted to a binary fraction.

At that point, you've already lost - using the bc math functions won't help. To use those correctly, you have to use string literals:

echo bcadd('0.00001','0.00001',20);

Will print:

0.00002000000000000000

OTHER TIPS

What is the max. amount of decimals I should display if I want it to be as accurate as possible?

Your problem starts with trying to get accurate values from floating point calculations. You cannot in general get accurate values from floating point calculations because of representation errors. The value 0.0001 cannot be represented exactly in binary floating point so the actual stored value will differ slightly from 0.0001 and that already gives you an inaccuracy. You should expect that the least significant digits will be inaccurate. Displaying more decimals doesn't make your calculation any more accurate - it just makes the inherent inaccuracies more visible.

If you need accuracy, you should either use a different datatype (bcadd does accept strings, but the conversion from a float to a string can still introduce an inaccuracy) or change your program to allow for answers that are slightly different from the precise answer.

If you just want to display a useful answer you can display it to the precision that makes sense for your application. If you are calculating the temperature to set an oven to cook a turkey then rounding the answer to a couple of significant figures should be fine. If you are doing scientific calculations you might want to display answers with 3, 4 or more significant figures. If you need 100% accuracy then you need to rethink your design.

"bcadd" requires three arguments. The first two are strings representing the left and right operands and one integer representing the decimal places in the result. This function outputs a string. Try using a string value instead of integers in your fifth result echo.

Also, regarding the precision of floating point numbers (from PHP.net):

The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).

Try using the BCMath library. It basically stores the number as a string but allows you to do arithmetic to it.

Handling Very Large or Very Small Numbers

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