Can anyone explain this PHP weirdness?

This code;

$a = (double)0.93;
$b = (double)0.05;
$c = (double)0.98;

echo "\\r\
" . '$a+$b = ' . ($a+$b) . ', type is ' . gettype($a+$b);
echo "\\r\
" . '$c = ' . $c . ', type is ' . gettype($c);

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

… produces this result;

$a+$b = 0.98, type is double
$c = 0.98, type is double
$a+$b does not equal $c

I have a solution (multiply by 100, convert to integers, then compare), but I’d like to understand why it’s happening.

If I change the values slightly (a=0.92, b=0.06), it works fine.

I understand that floats and doubles shouldn’t be compared, as rounding errors can give unexpected results, but this one seems fairly clear cut. It tells me twice that the values are doubles equal to 0.98, but fails on comparison. :confused:

Any light shed on the subject would relieve my mind greatly. :slight_smile:

Convert them to binary numbers of the appropriate length - of course then you’d never be able to tell what number was which.

Basically all languages have the same problem with floating point calculations - you are unlikely to get the exact answer you expect unless all of your fractions are able to be expressed in a form where the denominator is a power of 2 - eg 1/2, 1/4, 3/8, 7/16. 13/32, 154/1024, 2217/1048576 etc

So I guess there was a discrepancy between the variable displayed on screen and its internal representation. I wonder how to see the variables as PHP does internally?

Hi
You can try this way:


<?php 
$a =0.93;
$b =0.05;
$c =0.98;
$d = $a+$b;
if(bccomp($c, $a+$b, 2) == 0) {
echo 'equal';
} else {
echo 'not equal';
}
?>

Taken From PHP manual.
Floating point precision
It is quite usual that simple decimal fractions like 0.1 or 0.7 cannot be converted into their internal binary counterparts without a little 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 as the result of the internal representation really being something like 7.9999999999…

This is related to the fact that it is impossible to exactly express some fractions in decimal notation with a finite number of digits. For instance, 1/3 in decimal form becomes 0.3333333. . …

So never trust floating number results to the last digit and never compare floating point numbers for equality.