1

Some strange things are going on in my code. Could someone explain please why is this condition false?

When I output object's members with php's function var_dump(), I get this:

string(6) "105.63"
float(105.63)

from one object, and this is output from another object:

string(6) "667.69"
float(667.69)

Then I do comparison like this:

if(105.63 == "105.63"){
    echo "true";    
} else {
    echo "false";
}
if(667.69 == "667.69"){
    echo "true";
} else {
    echo "false";
}

it outputs 2 times true for sure, if we write code like in my example above. But in my class, it behaves differently. In first if I get false and in second if I get true. Then I looked to the data more deeply with var_export() function and it seems like I actually have following data:

'105.63'
105.6300000000000096633812063373625278472900390625

and

'667.69'
667.69000000000005456968210637569427490234375

So I decide to check wether my conditions work with that data... And they dont. Actually, only first one doesn't. Why do I get output false and true in following code?

if(105.6300000000000096633812063373625278472900390625 == "105.63"){
    echo "true";    
} else {
    echo "false";
}
if(667.69000000000005456968210637569427490234375 == "667.69"){
    echo "true";
} else {
    echo "false";
}

I know how to fix this. But I'm interested why conditions fails in first if.

EDIT

Php does type juggling when we use == comparison operator! Take a look at this:

var_export((float) "105.63");
var_export((string) 105.6300000000000096633812063373625278472900390625);
var_export((float) "667.69");
var_export((string) 667.69000000000005456968210637569427490234375);

outputs:

105.63
'105.63'
667.69000000000005
'667.69'

Should not this mean that the first condition be true and the second false? But I get false in first and true in second. Sorry if I was unclear.

ksno
  • 487
  • 1
  • 4
  • 21
  • 2
    [Floating point representation](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems) – Mark Baker Nov 03 '16 at 14:39
  • For the same reason you can't represent the ratio 1/3 in a decimal system using a finite amount of paper, binary has the same problem. Don't use `==` for floats, instead use `abs($number-$otherNumber) < $epsilon` where `$epsilon` is an arbitrarily small constant (precision). – apokryfos Nov 03 '16 at 14:44
  • check my edit please. – ksno Nov 03 '16 at 15:01

1 Answers1

3

Check the manual: http://php.net/manual/en/language.types.float.php

There is a big warning section about comparing floating point numbers:

WARNING

Floating point precision

Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded. Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118.... So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available. For a "simple" explanation, see the » floating point guide that's also titled "Why don’t my numbers add up?"

Why dont my numbers add up?

Cagy79
  • 1,610
  • 1
  • 19
  • 25