user198729
user198729

Reputation: 63626

How to fix this problem in PHP?

$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

Answers (5)

Michael Borgwardt
Michael Borgwardt

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

slebetman
slebetman

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

mjv
mjv

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

alemjerus
alemjerus

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

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

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

Related Questions