10

I recently start to learn PHP.

   <?php
    echo (int) ( (0.1+0.7) * 10 ); // prints '7', why not '8' ?
    ?>

Please convince me of this type-conversion process.

karim79
  • 339,989
  • 67
  • 413
  • 406
L.Lawliet
  • 319
  • 3
  • 10

6 Answers6

12

From PHP.net

It is typical that simple decimal fractions like 0.1 or 0.7 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.9.

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

Community
  • 1
  • 1
James Goodwin
  • 7,360
  • 5
  • 29
  • 41
  • +1, if only for the last paragraph quoted from PHP.net. Without using literally infinite memory, it is impossible to represent some fractions. This results in those fractions being represented as slightly less than what they should be (because they have to be truncated to a finite number of bits), thus the rounding errors. – Ryan Kinal Jun 30 '10 at 15:39
  • So no matter what number, it is truncated a little, even it is possible to save it with a finite number of bits(like 0.1+0.7)? – L.Lawliet Jun 30 '10 at 15:48
  • 3
    @L.Lawliet, try writing out a decimal like .1 or .7 in base 2 and see if you get a finite number. If you were using .5 or something else that can be easily converted into base 2, I don't think you'd have the same issue but unless you understand base conversion it isn't that obvious. – JB King Jun 30 '10 at 15:51
  • OMG.. I tried the similar code in C and got the same result. I indeed didn't notice this before when programming in other languages. So can I say all languages and scripts are processing numbers like this? – L.Lawliet Jun 30 '10 at 16:05
  • 1
    No, it depends of floating point representation used: http://en.wikipedia.org/wiki/Floating_point But most use same. – Imre L Jun 30 '10 at 16:22
  • James@ will u please share why this loss is happening while conversion?? – Rohit Feb 06 '14 at 09:15
7

You are running into floating point inaccuracy.

0.1 + 0.7 is not exactly 0.8, but slightly less. The cast to int simply truncates the value and yields 7 as the result.

To get the correct result use rounding:

<?php
    echo (int) round( (0.1+0.7) * 10 ); 
?>
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • I was going to explain that rounding the value will compensate for the loss of precision. – RobertPitt Jun 30 '10 at 15:33
  • "0.1 + 0.7 is not exactly 0.8, but slightly less." But what is the reason for this? PHP must have its consideration to be running like this. – L.Lawliet Jun 30 '10 at 15:41
  • See What Every Programmer Should Know About Floating-Point Arithmetic at http://floating-point-gui.de/basic/ or http://docs.sun.com/source/806-3568/ncg_goldberg.html for all the technical details. – Julien Roncaglia Jun 30 '10 at 15:50
2

As others have said, it's due to a loss of precision, as revealed by:

<?php
printf("%30.27f\n", (0.1 + 0.7) );
printf("%d\n", (int) (0.1 + 0.7) );
printf("%30.27f\n",  ( (0.1+0.7) * 10 ) );
printf("%d\n", (int) ((0.1 + 0.7) * 10) );
?>

which outputs:

0.799999999999999933386618522
0
7.999999999999999111821580300
7

GreenMatt
  • 18,244
  • 7
  • 53
  • 79
1

From http://php.net/manual/en/language.types.float.php

It is typical that simple decimal fractions like 0.1 or 0.7 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.9.

Anthony Potts
  • 8,842
  • 8
  • 41
  • 56
0

You're probably seeing a floating point rounding error, and when you int() it, it goes from being 7...9 to 7.

Daenyth
  • 35,856
  • 13
  • 85
  • 124
0

I am not sure, but this is probably because the int cast is truncating.

.1 + .7 might result in .799999999999999999999999 and

multiplying this by 10 = 7.9999999999999999999

(int) truncates this to 7.

tathagata
  • 478
  • 3
  • 12