Когда я устанавливаю PHP precision
установка значений 18
или выше (будь то в php.ini
или во время выполнения), round()
Функция дает неожиданные результаты. Это ошибка; или чего мне не хватает?
Например, результаты вокруг поплавка 12.4886724321
в 4
десятичная точность:
14: 12.4887
...
17: 12.4887
18: 12.4886999999999997
19: 12.48869999999999969
20: 12.48869999999999969
21: 12.4886999999999996902
22: 12.4886999999999996902
23: 12.488699999999999690203
24: 12.4886999999999996902034
Тестовый пример следующим образом:
$floaty = 12.4886724321;
for ($i = 14; $i <= 24; $i++) {
ini_set('precision', $i);
echo ini_get('precision') . ': ';
echo round($floaty, 4) . "\n";
}
Даже если я поставлю $floaty
чтобы просто 12.4
, Я получу 18: 12.4800000000000004
и т.д. для «экстраполированных» десятичных дробей. Что это за зона сумерек, в которую мы входим с точностью 18 или больше? Я знаю, как привести в порядок вещи для вывода, но я хотел бы знать, почему это происходит, и является ли это предполагаемым поведением.
Протестировано на PHP 7.0.2 @ W7x64 и PHP 5.6.8 @ CentOS 6.5 с идентичными результатами. number_format()
не делает этого, предположим, это более тупо (или нематематично) в том, как оно усекает десятичные дроби.
РЕДАКТИРОВАТЬ: Кажется, происходит со всеми математическими операциями? 1234.56 - 1233.03
повторяется с разной точностью:
12: 1.53
13: 1.53
14: 1.53
15: 1.52999999999997
16: 1.529999999999973
17: 1.5299999999999727
18: 1.52999999999997272
Числа с плавающей точкой в базе 10, такие как 0,1 или 0,7, не имеют точного представления в виде чисел с плавающей точкой в базе 2
увидеть http://floating-point-gui.de
PHP документы, чтобы плавать
увидеть Точность с плавающей точкой
Числа с плавающей точкой имеют ограниченную точность. Хотя это зависит от системы, PHP обычно использует формат двойной точности IEEE 754, который даст максимальную относительную ошибку из-за округления порядка 1.11e-16. Неэлементарные арифметические операции могут давать большие ошибки, и, конечно, распространение ошибок должно учитываться, когда несколько операций составлены.
Кроме того, рациональные числа, которые в точности представимы в виде чисел с плавающей запятой в базе 10, например 0,1 или 0,7, не имеют точного представления в виде чисел с плавающей запятой в базе 2, которая используется внутри, независимо от размера мантиссы. Следовательно, они не могут быть преобразованы в их внутренние двоичные аналоги без небольшой потери точности. Это может привести к сбивающим с толку результатам: например, floor ((0.1 + 0.7) * 10) будет обычно возвращать 7 вместо ожидаемых 8, поскольку внутреннее представление будет что-то вроде 7.9999999999999991118 ….
Поэтому никогда не доверяйте результатам с плавающей запятой последней цифре и не сравнивайте числа с плавающей запятой непосредственно на равенство. Если требуется более высокая точность, доступны математические функции произвольной точности и функции gmp.
Других решений пока нет …