Почему floor(0.99999999999999999) = 1 и floor(0.9999999999999999) = 0?

Функция пола в PHP ведет себя странно. Для 16 десятичных значений это дает минимальное значение, но при увеличении 1 десятичного знака оно округляется.

$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. Это где-то определено / объяснено, в какой момент оно дает "круглое" значение?
  2. Есть ли функция, которая дает 0 во всяком случае, сколько 9 в десятичных?

2 ответа

Решение

Это не floor что раунды, это математика с плавающей точкой, которая делает.

Эта строка:

echo 0.99999999999999999;

Печать 1 ( демо), потому что 0.99999999999999999 является слишком точным, чтобы быть представленным (64-битным?) с плавающей точкой, поэтому берется самое близкое возможное значение, которое оказывается 1,
0.99999999999999994 также слишком точен, чтобы быть точно представленным, но здесь самое близкое представимое значение 0.9999999999999999,

  1. Это где-то определено / объяснено, в какой момент оно дает "круглое" значение?

Это сложно, но цифры округляются почти всегда.
Я полагаю, что нет определения "от того, когда значения будут аппроксимированы", но это математическое свойство, которое следует из определений в стандарте IEEE 754 с плавающей запятой.
Чтобы быть в безопасности, просто предположите, что все приблизительно.

  1. Есть ли какая-либо функция, которая в любом случае дает 0, сколько 9 в десятичных числах?

Проблема в том, что для PHP 0.99999999999999999 буквально так же, как 1,
Они представлены одной и той же последовательностью битов, поэтому их невозможно различить.

Есть несколько решений для работы с десятичными числами с большей точностью, но для этого требуются серьезные изменения кода.
Возможно, вас интересует

Работа с большими числами в PHP

Обратите внимание, что, хотя вы можете получить произвольную точность, вы никогда не получите бесконечной точности, так как для этого потребуется бесконечное количество памяти.

Также обратите внимание, что если вы на самом деле имели дело с бесконечной точностью, 0.999... (происходит вечно) будет действительно (как в, математически доказуемо) равно 1, как подробно объясняется в этой статье Википедии.

$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;

на моей машине разработки такое поведение происходит с цифрой "15", а не "17", как у вас. PHP округляет последнюю цифру в плавающих числах. ваш floor() функция не имеет ничего общего с этим поведением

Другие вопросы по тегам