Search code examples
phpnumbersfloating-accuracy

Float number behavior


My roommate just came up with a question.

Why in php (maybe other languages as well) floor($foo) and (int)$foo is 7?

$foo = (0.7 + 0.1) * 10;
var_dump(
    $foo,
    floor($foo),
    (int)$foo,
    ceil($foo),
    is_infinite($foo),
    is_finite($foo));

result

float(8)
float(7)
int(7)
float(8)
bool(false)
bool(true)

Notice that $foo is not an infinite number.

From answers I can see that everyone says that it is actually x.(9)

But what is reason behind number being x.(9) and not actual x as it should be in real life?


Solution

  • A rational number will become a repeating decimal if the denominator contains a prime factor that isn't among the ones in the base's prime factor list (i.e. 2 and 5)

    • A rational number has an infinitely repeating sequence of finite length less than the value of the fully reduced fraction's denominator if the reduced fraction's denominator contains a prime factor that is not a factor of the base. The repeating sequence is preceded after the radix point by a transient of finite length if the reduced fraction also shares a prime factor with the base.

    https://en.wikipedia.org/wiki/Repeating_decimal

    Floating-point types in computers are almost always in binary, so any number whose denominator in the rational representation is not a power of 2 would be an infinite periodic decimal. For example 0.1 would be rounded to 0.100000001490116119384765625 in IEEE-754 single precision which is the nearest sum of power of 2s

    Here none of 0.7 and 0.1 are representable in binary floating-point, and neither is 0.8. Their sum is also not equal to 0.8: try printing 0.7 + 0.1 == 0.8 and you'll get the result as false. It's actually slightly less than 0.8. But it's not a repeating decimal like 7.(9) as you though but a value with a finite number of 9s in the fractional part.

    As a result the ceil and int result in 7. If you take the floor or round result you'll get 8