Reputation: 14843
I have an associative array whose values are floats, which are supposed to be probabilities. As such, I sum them up and require that the result is in fact 1.
$total = array_sum($array);
echo '$total = '.$total."\n";
if ($total == 1) {
die("total is 1");
} else {
die("total is not 1");
}
This mysteriously outputs:
$total = 1
total is not 1
Doing a var_dump($total)
yields float(1)
, and yet even $total == (float)1
returns false.
What's going on?
Upvotes: 6
Views: 449
Reputation: 116528
Floating point values are by nature imprecise and are very rarely equal to one another due to the way they are stored and rounding errors. You should be comparing floats by seeing if the two values are "close enough". That is, comparing the absolute value of the difference between the two values to a significantly small margin of error (often referred to as "epsilon").
One such implementation may be:
if (abs($total - 1) < 0.000000001)
die("total is 1");
} else {
die("total is not 1");
}
Note that only your application's requirements can truly determine what a safe margin of error is and at what point numbers should be rounded for display.
If you are dealing with currency values, for example, and require exact precision, a better solution would be to forgo floating-point arithmetic entirely. One option in this case would be to use an integer type and store the number as cents, dividing only at the last minute to display the number to the user (or not even dividing, and injecting a decimal point into the string instead).
Upvotes: 4
Reputation: 6476
Cast to int doing
if ((int)$total == 1)
And it will work :)
EDIT: or even better
$total = (int)array_sum($array);
Upvotes: 1
Reputation: 1433
Floats in php (and other languages) are not precise, therefore (float)1
might actually be 1.00000000000000123113
or .99999999999999823477
See answer PHP - Floating Number Precision for more information
Upvotes: 2