问题
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