6

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?

Mala
  • 14,178
  • 25
  • 88
  • 119
  • 2
    http://stackoverflow.com/questions/4682889/is-floating-point-ever-ok – thumbmunkeys Sep 06 '13 at 17:20
  • Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – miken32 Nov 30 '18 at 00:13
  • @miken32 not quite. That question is about general floating point arithmetic issues. This question is about PHP's var_dump function unexpectedly performing rounding (rather than dumping the var) – Mala Dec 02 '18 at 01:32

3 Answers3

4

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).

lc.
  • 113,939
  • 20
  • 158
  • 187
2

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

Community
  • 1
  • 1
Jordan
  • 1,433
  • 8
  • 14
  • is there a way to get php to tell me what its actual value is? – Mala Sep 06 '13 at 17:23
  • `print(number_format($myNumber, 32);` should let you see the with some degree of precision what it is, but as far as I know, you cannot see the _exact_ value. – Jordan Sep 06 '13 at 17:25
  • whargbl "0.99999999999999988897769753748435" - i had no idea var_dump would round like that – Mala Sep 06 '13 at 17:27
1

Cast to int doing

if ((int)$total == 1)

And it will work :)

EDIT: or even better

$total = (int)array_sum($array);
Quillion
  • 6,346
  • 11
  • 60
  • 97
  • 1
    this would unfortunately be unhelpful with what i'm trying to do (see the top of the question). If my values were screwed up -- what this code is there to check -- and the sum were in fact 1.3 it'd pass the test – Mala Sep 06 '13 at 17:29