6

Could someone please explain what is going on here?

echo (18.99 * 100); // output: 1899

echo (int)(18.99 * 100); // output: 1898

The only thing I can possibly think of is that the 1899 is actually 1898.999999999999 or something and PHP is converting it as part of echo somehow? If this is the case, why? If not, what is the reason for this strange behaviour?

Eva
  • 4,859
  • 3
  • 20
  • 26
  • well, you think correctly. int is trimming the decimal part, and it has to do with the representation of floating point. read http://en.wikipedia.org/wiki/Floating_point – galchen Dec 24 '13 at 10:07
  • It sort of is. You've run into a floating point precision issue. http://stackoverflow.com/questions/14587290/can-i-rely-on-php-php-ini-precision-workaround-for-floating-point-issue – bcmcfc Dec 24 '13 at 10:08
  • You can not count on exactness with floating point numbers, unless you're only ever using powers of two or multiples thereof. The second you can't represent a number as (integer)*2^(integer), you've introduced rounding error. – cHao Dec 24 '13 at 10:08
  • how and why, then, is PHP converting it with `echo` instead of outputting the true value? – Eva Dec 24 '13 at 10:10
  • @Evan: Because when your number is in the thousands, no one cares about .000000000001, but they do care about reasonable-looking numbers. Plus, if it didn't, you'd be freaking out over why your 18.99 was actually 18.989999999995 :) – cHao Dec 24 '13 at 10:13
  • @cHao no I mean I think that's why I'd cast it as an integer or use `round()`.. or am i missing something? like if this is the case why shouldn't `(int)` behave the same as `echo` in not caring about extreme fractions? – Eva Dec 24 '13 at 10:16
  • @Evan Because the cast is a *truncation* (to integer), not a *rounding* (for display/string) operation. – user2864740 Dec 24 '13 at 10:16
  • @Evan: Because `(int)` doesn't care about appearances; it cares about the exact value. The exact value was less than 1899. So it's 1898 now. – cHao Dec 24 '13 at 10:17
  • 4
    `18.99 * 100` is actually `1898.999999999999772626324556767940521240234375`: http://ideone.com/k0QMzC – Crozin Dec 24 '13 at 10:18
  • hmm OK - so then what exactly is `echo` doing and what conditions does it use to determine when to display floats as ints? (as in the case above) – Eva Dec 24 '13 at 10:18
  • @user2864740 i see - just curious - is there any way to turn this behaviour off? – Eva Dec 24 '13 at 10:20

1 Answers1

5

from manual:

When converting from float to integer, the number will be rounded towards zero.

If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms), the result is undefined, since the float doesn't have enough precision to give an exact integer result. No warning, not even a notice will be issued when this happens!

Warning

Never cast an unknown fraction to integer, as this can sometimes lead to unexpected results.

<?php
echo (int) ( (0.1+0.7) * 10 ); // echoes 7!
?>

Read here

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

in your case may be 18.99*100=1898.999999999999772626324556767940521240234375 so int truncated it to 1898.

R R
  • 2,999
  • 2
  • 24
  • 42