3

floor function in PHP behave weirdly. For 16 decimal values it gives floor value but by increasing 1 decimal it round.

$int = 0.99999999999999999; 
echo floor($int); // returns 1 

$int = 0.9999999999999999; 
echo floor($int); // returns 0

$int = 0.99999999999999994; 
echo floor($int); // returns 0
  1. Is it defined/explained somewhere, at which point it gives "round" value?
  2. Is there any function which gives 0 anyhow how many 9 in decimals?
Somnath Muluk
  • 55,015
  • 38
  • 216
  • 226

2 Answers2

14

It's not floor that rounds, it's floating point math that does.

This line:

echo 0.99999999999999999;

Prints 1 (demo) because 0.99999999999999999 is too precise to be represented by a (64-bit?) float, so the closest possible value is taken, which happens to be 1.
0.99999999999999994 is also too precise to be represented exactly, but here the closest representable value happens to be 0.9999999999999999.

  1. Is it defined/explained somewhere, at which point it gives "round" value?

It's complicated, but the numbers are rounded almost always.
I believe there is no definition of "from when values will be approximated", but that is a mathematical property that follows from the definitions in the IEEE 754 floating point standard.
To be safe, just assume everything is approximated.

  1. Is there any function which gives 0 anyhow how many 9 in decimals?

No. The problem is that, for PHP, 0.99999999999999999 is literally the same as 1.
They're represented by exactly the same sequence of bits, so it can't distinguish them.

There are some solutions to work with bigger precision decimals, but that requires some major code changes.
Probably of interest to you:

Working with large numbers in PHP

Note that while you may get arbitrary precision, you will never get infinite precision, as that would require infinite amounts of storage.

Also note that if you actually were dealing with infinite precision, 0.999... (going on forever) would be truly (as in, mathematically provable) equal to 1, as explained in depth in this Wikipedia article.

Siguza
  • 21,155
  • 6
  • 52
  • 89
  • 2
    Two usefuls links to understand it better: http://www.binaryconvert.com/result_double.html?decimal=048046057057057057057057057057057057057057057057057057057 and http://www.binaryconvert.com/result_double.html?decimal=048046057057057057057057057057057057057057057057057057 – Blackhole Oct 23 '15 at 09:54
  • actually it's double precision 64-bit float, which can be precise to ~15-16 digits. single precision can only be precise to ~7 digits – phuclv Oct 23 '15 at 10:10
0
$float_14_digits = 0.99999999999999;
echo $float_14_digits; // prints 0.99999999999999
echo floor($float_14_digits); // prints 0

$float_15_digits = 0.999999999999999;
echo $float_15_digits; // prints 1
echo floor($float_15_digits); // prints 1
exit;

on my development machine that behavior happens on digit '15' not '17' like yours. PHP rounds the last digit in the floating numbers. your floor() function has nothing to do with this behavior

Accountant م
  • 6,975
  • 3
  • 41
  • 61