Странное поведение с плавающей запятой PHP

Имеет странную проблему:

$testTotal = 0; foreach($completeBankArray as $bank){ var_dump($testTotal); echo " + "; var_dump(floatval($bank["amount"])); echo " = ".(floatval($testTotal) + floatval($bank["amount"]))."</br>"; $testTotal = floatval(floatval($testTotal) + floatval($bank["amount"])); 

И это результат, который я получаю:

 ------------------//-------------------- float(282486.09) + float(15) = 282501.09 float(282501.09) + float(3.49) = 282504.58 float(282504.58) + float(22.98) = 282527.55999999 float(282527.55999999) + float(5.2) = 282532.76 float(282532.76) + float(39.98) = 282572.73999999 float(282572.73999999) + float(2.6) = 282575.33999999 float(282575.33999999) + float(2.99) = 282578.32999999 ------------------//----------------------- 

Как это возможно, что я делаю?

Вы ничего не делаете неправильно. Поплавки, как известно, неточны. Из документов (в огромном красном предупреждающем поле):

Числа с плавающей запятой имеют ограниченную точность. Хотя это зависит от системы, PHP обычно использует формат двойной точности IEEE 754, который даст максимальную относительную ошибку из-за округления порядка 1.11e-16. Неэлементарные арифметические операции могут приводить к большим ошибкам, и, разумеется, распространение ошибок должно учитываться, когда несколько операций усугубляются.

Кроме того, рациональные числа, которые точно представлены в виде чисел с плавающей запятой в базе 10, например 0,1 или 0,7, не имеют точного представления в виде чисел с плавающей запятой в базе 2, которые используются внутри, независимо от размера мантиссы. Следовательно, они не могут быть преобразованы в их внутренние двоичные копии без небольшой потери точности. Это может привести к запутывающим результатам: например, пол ((0,1 + 0,7) * 10) обычно возвращает 7 вместо ожидаемого 8, так как внутреннее представление будет чем-то вроде 7.9999999999999991118 ….

Поэтому никогда не доверяйте значениям с плавающим числом до последней цифры и не сравнивайте числа с плавающей запятой непосредственно для равенства. Если требуется более высокая точность, доступны произвольные математические функции точности и функции gmp .

Поплавки никогда не являются точными и будут сильно отличаться в долгосрочной перспективе. Если вы работаете с математикой точности, прочитайте о библиотеке bc .

Пример классической цифровой точности. Компьютеры хранят номера с плавающей запятой в двоичном формате.

Короткий ответ заключается в том, что компьютер не может точно представлять некоторые числа с плавающей запятой в двоичном формате.

Длительный ответ предполагает перемещение между численными основами. Если у вас есть float, вы не можете полностью представлять его в двоичном выражении, если только знаменатель не может быть разбит на факторы, которые имеют степень 2.

Другие ответы дали некоторое представление о том, почему вы получаете это поведение с поплавками.

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