PHP is erroring out on me when working with small decimals / floats. Take the following code:
$spotPrices['entry'] = 1.6591;
$price['o'] = 1.65908;
$currentresult = $spotPrices['entry'] - $price['o'];
echo $currentresult;
I would expect this to output 0.00002 (the answer). But instead it outputs: -1.99999999999E-5
Why is it doing this and, more importantly, how can I get the correct result?
I've done some searching on the forums and seen that floating points give PHP fits but haven't seen a solution or workaround that seems to answer my question.
My calculator is saying that the result should be 0.00002
use number_format:
$currentresult = number_format($spotPrices['entry'] - $price['o'], 8);
Instead of 0.00002 you get 1.9999999999909E-5 which is 0.000019999999999909. This is due to floating point precision. Precision is platform-dependent. You can read up on it here: http://www.php.net/manual/en/language.types.float.php
Related
I am currently investing a rounding problem in PHP.
I've tested it here https://3v4l.org/NpRPp and it seems to be the same, since ever.
But is this correct behaviour? Because i expected the following.
echo round(908.5449, 2, PHP_ROUND_HALF_UP); // should be 908.55, but returns actually 908.54
Can someone tell if this behaviour is intended, and if so, how to solve it properly for every possible floating point number?
Edit: Thanks to the answers, this behaviour is correct but i expected the wrong result. My original number in the program was 908.55 which somewhere in the chain of the program became 908.5449999999994 due to storage in DB and floating point precision issues. So i wanted it to be 908.55 again, which does not work with regular use of round().
This is working correctly. The output of
echo round(908.5449, 2, PHP_ROUND_HALF_UP);
Should be 908.54. You're rounding to two decimals, so the remainder, that is rounded off is 0.0049. This is less than 0.005, which would be half, so it is rounded down.
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
I have this simple substraction code:
<?php
$n1 = 257931.076;
$n2 = 257930;
echo $n1 - $n2;
?>
Why i got 1.0760000000009 instead of 1.076
Where did the 0000000009 came from? i need precise result and i don't want to use round() or number_format() because sometime i have more than 3 decimal, for example: 12345.678912, anyone know?
I have tried to use round() or number_format() but it only for fixed decimal point, not dynamic
As #GordonM perfectly explained it, you cannot expect exact results when using floating point values.
You can use a library such as brick/math to perform exact calculations on decimal numbers of any size:
use Brick\Math\BigDecimal;
$n1 = BigDecimal::of('257931.076'); // pass the number as a string to retain precision!
$n2 = 257930;
echo $n1->minus($n2); // 1.076
The library uses GMP or BCMath internally when available, but can work without these extensions as well (with a performance penalty).
For technical reasons that every programmer should be aware of, IEEE floating point numbers simply can't represent numbers precisely and will use the closest approximation they can when storing them (In fact the only fractions that can be stored perfectly have denominators that are powers of 2 (1/2, 1/4, 1/8, 1/16, etc. All other values are approximations). PHP has an ini value called "precision", which controls how many digits are considered significant WHEN OUTPUTTING floating point values. It defaults to 14, with any digits after that hidden.
However, the actual value stored may try to approximate the desired value with far more digits than that. If you change precision, you'll see what is really being stored.
php > $test = 0.1;
php > var_dump ($test);
php shell code:1:
double(0.1)
php > ini_set("precision", 100);
php > var_dump ($test);
php shell code:1:
double(0.1000000000000000055511151231257827021181583404541015625)
php > var_dump (0.25);
php shell code:1:
double(0.25)
php > var_dump (0.4);
php shell code:1:
double(0.40000000000000002220446049250313080847263336181640625)
What can you actually do about this? Not a great deal, this is just a consequence of how floating point works. You can try to avoid using floating point if you need exact values (for example when dealing with money amounts, store 3.99 as 399 pennies/cents instead of 3.99 pounds/dollars), or you can use the "bugnum" libraries that are available in PHP, GMP and BC_Math, but these are both tricky to use and have their own sets of gotchas. They can also be hard on storage and/or processor time. In most cases it's best to just live with it and be aware that when you're dealing with floating point you're not dealing with an exact representation.
I do not understand php:
echo -0.01-0.02-0.16+0.01+0.01+0.17;
result 2.7755575615629E-17
correctly = 0 !
E-17 really means x 10 ^ (-17).
According to the computer, which suffers from precision errors at the far end of decimal floating point numbers, it is calculating your answer to be 0.00000000000000002775557...
If you don't need that sort of precision, you can force rounding to a certain accuracy:
echo round(-0.01-0.02-0.16+0.01+0.01+0.17, 8);
The answer you got is accurate answer according to BODMAS rule if you want round up answer than just use round() function of PHP. You will get you answer.
echo round(-0.01-0.02-0.16+0.01+0.01+0.17, 8);
I'm having a weird problem where PHP's sprintf seems to be changing some numbers. This doesn't happen all the time, just occasionally.
The following code:
echo sprintf('%04d',$product['priceUSD']*100)."(".($product['priceUSD']*100).")";
generates the following output for a $19.99 product: 1998(1999)
I can work around this, but I'd love to know why it is doing it, and if there's any method to the apparent madness.
Update:
It looks like it's happening when converting from float to int. The following gives the same output:
echo (int)($product['priceUSD']*100)."(".($product['priceUSD']*100).")";
echo sprintf('%.2f',$product['priceUSD']*100)."(".sprintf('%.2f',$product['priceUSD']*100).")";
What number format are you looking for?
First off: %d is kinda like an (int) cast.
19.99 = 1.99899999999999984368059813278E1 = 0x4033FD70A3D70A3D
in IEEE 64 Bit.
if we multiply that in floating point with 100 we get 1998.99999999999984368059813278E1 casted to int is 1998.
"19.99 is just one of those numbers..." (see #Dragons Link)
for exact results use bcmath extension:
echo sprintf('%4d', bcmul ($price,100));
To stabilize your multiplication while facing floating point arithmetic problems, leverage the bcmul() function to multiply the two numbers.
Secondarily, I should mention that printf() will perform rounding, but (int) will not.
Code: (Demo)
$product['priceUSD'] = '19.99';
printf('%04d', bcmul($product['priceUSD'], 100));
Output:
1999
I have this example
$x = 0.154 + 0.408;
$y = 0.562;
echo $x - $y;
You would think it's 0 but it's not ( well maybe it depends on your system and php version ).
Anyway for those who don't see 0, what's the correct way to do float operations ?
$x = bcadd (0.154 ,0.408);
$y = 0.562;
echo bcsub($x,$y);
It's actually not related to the PHP itself, that's how computers work - some numbers cannot be reprezented precisely so you have to keep in mind that when you work with floats and doubles you work on numbers approximations.
You can read more about floating point on Google: floating point arithmetic
You really should understand the problem (there is no library which can magically solve this problem, PHP is all you need).
A very good article you can find here, it's actually written for Delphi, but the problem is not specific to any language:
Comparing floating point values
Please also read the warning in the documenation of PHP:
Floating point precision