Если все еще кто-то попадет на эту страницу с похожими проблемами, где вычитание чисел с плавающей запятой вызывает ошибку или странные значения. Я хочу объяснить эту проблему немного подробнее. Виновником являются числа с плавающей запятой. Чтобы проиллюстрировать проблему, я объясню, почему на простом примере, и вы сможете предположить, почему это влияет на округление и т. Д.
Это не имеет прямого отношения к PHP и не является ошибкой. Однако каждый программист должен знать об этой проблеме.
Эта проблема даже унесла много жизней два десятилетия назад.
25 февраля 1991 г. эта проблема с вычислением плавающих чисел в ракетной батарее MIM-104 Patriot не позволила ей перехватить приближающуюся ракету «Скад» в Дахране, Саудовская Аравия, что привело к гибели 28 солдат из 14-го квартирмейстерского отряда армии США.
Но почему это происходит?
Причина в том, что значения с плавающей запятой представляют ограниченную точность. Таким образом, значение может иметь другое строковое представление после какой-либо обработки. Это также включает в себя запись значения с плавающей запятой в ваш скрипт и прямую его печать без каких-либо математических операций.
Простой пример:
$a = '36';
$b = '-35.99';
echo ($a + $b);
Вы ожидаете, что он напечатает 0,01, верно? Но он напечатает очень странный ответ вроде 0.009999999999998.
Как и другие числа, числа с плавающей запятой типа double или float хранятся в памяти в виде строки, состоящей из 0 и 1. Отличие плавающей запятой от целого заключается в том, как мы интерпретируем 0 и 1, когда хотим на них взглянуть. Существует множество стандартов их хранения.
Числа с плавающей запятой обычно упаковываются в компьютерные данные в виде бита знака, поля экспоненты и мантиссы или мантиссы слева направо....
Десятичные числа плохо представлены в двоичном формате из-за нехватки места. Итак, вы не можете выразить 1/3 в точности как 0,3333333..., верно? По той же причине мы не можем представить 0,01 как двоичное число с плавающей запятой. 1/100 равно 0,00000010100011110101110000..... с повторяющимся 10100011110101110000.
Если 0,01 хранится в упрощенной и усеченной системой форме 01000111101011100001010 в двоичном формате, то при переводе обратно в десятичное число оно будет читаться как 0,0099999.... в зависимости от системы (64-битные компьютеры дадут вам гораздо лучшую точность, чем 32-битные). ). В этом случае операционная система решает, печатать ли ее так, как она видит, или как сделать ее более удобочитаемой. Таким образом, это зависит от машины, как они хотят это представить. Но его можно защитить на уровне языка разными методами.
Если вы форматируете результат, echo number_format(0.009999999999998, 2); он напечатает 0,01.
Это потому, что в этом случае вы указываете, как его следует читать и какая точность вам требуется. Ссылки: 1,2,3,4,5
person
Selay
schedule
18.12.2014
sprintf('%.2f', $n)
? - person binaryLV   schedule 07.02.20111111111.5049999999
. Значения с плавающей запятой по своей природе неточны. А в PHP5.3, вероятно, просто больше эвристики. - person mario   schedule 07.02.2011printf('%.10f', 1111111.505)
печатает1111111.5049999999
. - person binaryLV   schedule 07.02.2011