Если кто-то все еще посещает эту страницу с подобными проблемами, где вычитание с плавающей точкой вызывает ошибку или странные значения.
Я хочу объяснить эту проблему немного подробнее. Виновником является числа с плавающей запятой.
И разные операционные системы и разные версии языков программирования могут вести себя по-разному.
Чтобы проиллюстрировать проблему, я объясню почему на простом примере ниже.
Он не имеет прямого отношения к 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.
Это потому, что в этом случае вы указываете, как следует читать и какую точность вам требуется.