Strange addition of numeric strings in PHP

社会主义新天地 提交于 2019-12-04 05:19:30

问题


I'm adding together two numerical strings $a and $b and then comparing the result against another numerical string $c. All three numbers are stored as strings, and being converted to floats by PHP at the comparison step.

For some reason, the test $a+$b == $c does not evaluate as true, even though it should.

You can recreate the problem with this script:

<?php
$a = "-111.11";
$b = "-22.22";
$c = "-133.33";

echo '$a is '.$a."\n";
echo '$b is '.$b."\n";
echo '$c is '.$c."\n";
echo '$a + $b is '.($a+$b). "\n";

if ($a + $b == $c) {
    echo 'a + b equals c'."\n";
} else {
    echo 'a + b does not equal c'."\n"; 
}
?>

Weirdly, if I change the values slightly so that $a=-111.11, $b=-22.23 and $c=-133.34 it works as expected.

Am I missing something obvious, or is this a bug with PHP?


回答1:


You're running into a limitation of floating point arithmetic. Just as there are certain numbers you can't represent exactly in decimal (1/3 for instance), so there are certain numbers you can't represent exactly in floating point binary.

You should never try and compare floating point numbers for equality, as the limitations of floating point make it unlikely that the variables you're comparing have an actual value that matches exactly the value you think they have. You need to add a "fudge factor", that is if the two numbers are similar to within a certain tolerance, then you should consider them to be equal.

You can do this by subtracting one number from another and seeing if the absolute result is below your threshold (in my example, 0.01):

if (abs ($someFloatingPointNumber - $someOtherFloatingPointNumber) <= 0.01)
{
    // The values are close enough to be considered equal
}

Of course, this combined with rounding errors that can creep in with successive mathematical operations mean that floating point numbers are often not the best choice anyway, and should be avoided where possible. For example, if you're dealing with currency, store your values as integers in the minor unit (pennies for GBP, cents for USD, etc), and only convert to the major unit by dividing by 100 for display.




回答2:


From the large red box on this page: http://php.net/manual/en/language.types.float.php

never compare floating point numbers for equality.

Basically, you're not getting the correct numbers, because they are saved in a slightly different format, so when you compare, it gets screwed.

That link of @Corbin is really good, So I'm adding it just for the love :)
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

What Every Computer Scientist Should Know About Floating-Point Arithmetic

This paper presents a tutorial on those aspects of floating-point that have a direct impact on designers of computer systems. It begins with background on floating-point representation and rounding error, continues with a discussion of the IEEE floating-point standard, and concludes with numerous examples of how computer builders can better support floating-point.




回答3:


Do your number have always two decimal positions?

If so, you can try this:

$aDec = round($a * 100);
$bDec = round($b * 100);
$cDec = round($c * 100);

if ($aDec + $bDec == $cDec) {
    ...
}


来源:https://stackoverflow.com/questions/8423270/strange-addition-of-numeric-strings-in-php

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!