paperino00

04-12-2012, 05:28 PM

Hello, I wrote this php code for show a string when a variable is equal to 3, but it print 3 instead of the string, do you know why?

Thank you!

<?php

for($a=0.03;$a<=9;$a=$a+0.03)

{

if($a==3)

echo "Equal to 3";

else

echo $a. " ";

}

?>

Fou-Lu

04-12-2012, 05:54 PM

This is a precision error (defined by IEEE standards and requires knowledge of floating point arithmetic and how a machine represents floats).

Effectively, you need to calculate based to epsilon, or a "close enough" number. Alternatively, treat it as an integer for all steps, and display it as a float of the int / 100 when it comes time to display.

function cmpFloat($f1, $f2, $epsilon)

{

return abs($f1 - $f2) < $epsilon; // ie: our number is "close enough"

}

$epsilon = pow(2, -24);

for($a=0.03;$a<=9;$a=$a+0.03)

{

if(cmpFloat($a, 3.0, $epsilon))

{

echo "Equal to 3" . PHP_EOL;

}

else

{

echo $a . " " . PHP_EOL;

}

}

For a bit more info refer here: http://www.php.net/manual/en/language.types.float.php#language.types.float.comparison and here: http://en.wikipedia.org/wiki/Machine_epsilon

paperino00

04-12-2012, 10:37 PM

So it require the number to be rounded and limited?

Why does this code work without any other operations?

$a= 3.03;

if($a==3.03)

echo "Ok";

Fou-Lu

04-13-2012, 01:51 AM

No, the numbers are not rounded explicitly, but must be checked for a close enough result. This is a flaw with binary representation of floats and how they are limited in the mantissa and exponent values, and is an inherit flaw in all languages as its the limitation in its storage, not that of the calculation.

We won't go into this as its quite complicated and I don't think I still have my old math notes. Floats are stuck to 24 bits of precision: 1 bit sign, 8 bit exponent and 23 bit mantissa. So the limitation here is 23 bits before it starts truncating. Stack onto it the approximation (base 10 cannot divide 1/3 to an even number; binary cannot divide 1/10 for the same reason; therefore 0.1 is not actually representable in binary as you end up with 1100110011001100----), and you start seeing loss during arithmetic calculations. It compensates with a truncation.

You cannot trust an accurate comparison between a calculated result of 3.03 and a value of 3.03. You must use a comparison value to determine if its close enough (known as the machine epsilon, which in PHP should be 2^-24). So long as its different isn't out by more than that value, its considered to be the same value.