Reputation: 63626
$onethird = 1.0/3;
$fivethirds = 1.0/3+1.0/3+1.0/3+1.0/3+1.0/3;
$half = 1.0/2;
$threehalf = 1.0/2+1.0/2+1.0/2;
var_dump($onethird + $fivethirds == $half + $threehalf);
which outputs false
,but as we all know:5/3+1/3=2=3/2+1/2
How to fix this problem?
Upvotes: 5
Views: 248
Reputation: 346250
How to fix this problem?
What actual Problem do you want to solve? Your code just shows that floating point numbers have limited accuracy - that's nothing new.
For most real-world applications, the input that isn't 100% accurate anyway, and the result just needs to be accurate to a couple of decimal places. Equality comparisons simply aren't something you need most of the time. If you do, you can fudge it by seeing whether the result is within some predefined small distance from a given number.
If you need decimal math with specific precision, use the BC Math functions - but realize that those are very slow if used for complex calculations.
Upvotes: 1
Reputation: 113876
var_dump(abs($onethird + $fivethirds - $half + $threehalf) < 0.00001);
see: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm also: http://docs.sun.com/source/806-3568/ncg_goldberg.html
This is true in all programming languages.
I have not yet come accross any language where this is done automatically when programmers want equality of floats. Someone should come up with a new operator, perhaps =~= for float equality which would automatically do the comparison of diff with epsilon:
if ($float1 =~= $float2) {...
It is annoying that every year, since I graduated in 2000, around this time of the year some newbie will ask this question on some newsgroup, forum or mailing list. Just last month I answered this on comp.lang.tcl. And it's not just newbies, two months ago I had to explain this to my coworker who has been developing software for over 5 years asking me why his Perl code is doesn't work.
Upvotes: 1
Reputation: 75095
The problem comes from the small errors introduced by Floating Point arithmetic. This is not specific to PHP.
You can fix this by introducing a small "tolerance" factor, i.e. by checking that the first value in the comparaision is >= the second value minus the tolerance and <= the second value plus the tolerance.
Upvotes: 4
Reputation: 8268
It depends of how precise your comparison should be
In this case, you should use bccomp() instead of "=="
see http://php.net/manual/en/language.types.float.php
Upvotes: 2
Reputation: 798456
This is one of the problems with the IEEE 754 representation of floating point numbers; the representations are not accurate enough to represent all rational numbers.
The way to do it is to compare the difference against a very small number for closeness, rather than equality:
abs(($onethird + $fivethirds) - ($half + $threehalf)) < 1e-8
Upvotes: 5