math — round () прерывается, когда точность PHP установлена ​​на 18+

Когда я устанавливаю 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

3

Решение

Числа с плавающей точкой в ​​базе 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.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]