Странное дело, но это правда — сумма .1 и .2 не будет равняться .3.
Рассмотрим на примере:
if ((0.1 + 0.2) == 0.3) { echo '1'; } else { echo '0'; }
Вы получите 0. На первый вгляд это странно и возможно нужно явно указать, что мы работаем с числами с плавающей точкой:
if (((float)0.1 + (float)0.2) == (float)0.3) { echo '1'; } else { echo '0'; }
Результатом подобного сравнения также будет 0. А что если продебажить результат выражения?
var_dump(0.1 + 0.2); // результат будет: float(0.3)
Как видим мы получаем в итоге тип float и значение 0.3.
Так в чем же дело? Почему так происходит?
Суть проблемы сравнения состоит в том, что в данном случае мы работаем с числами округляя их до десятых и чтобы видеть картину целиком, давайте округлим до… 17(!)го знака:
ini_set('precision', 17); var_dump(0.1 + 0.2); // Результат будет: float(0.30000000000000004)
Немного странный результат, правда? А все потому, что Вы видите и работате с простыми дробями, но компьютер оперирует двоичными числами. Таким образом перед выполнением выражения он переводит десятичное представление чисел в двоичное — нули и единицы.
Затем следует знать, что при переводе в двоичную систему, некоторые числа имеют бесконечную (либо очень большую) дробь, а так как на хранение чисел выделяется ограниченное кол-во памяти в системе — они окргуляются/обрезаются по стандарту IEEE 754. И вот накопленные округления дают на выходе такие погрешности и как результат — неточность вычисления.
Конкретно в нашем примере проблема с 0.1 — это число не может быть точно представлено в двоичной системе.
Так как сравнить сумму 0.1 + 0.2 с 0.3?
Вариант №1.
Для функции bcadd необходимо добавить библитеку PHP — php7.1-bcmath. В противном случае вы получите ошибку уровня Fatal.
// функция вернет сумму двух чисел с плавающей точкой и с указанным огруглением $test = bcadd(0.1, 0.2, 1); var_dump($test); // результатом будет: string(3) "0.3"
Результат будет типа string!
if ($test == 0.3) { echo '1'; } else { echo '0'; }
PHP сам приведет $test к нужному типу данных и в этом случае результатом сравнения будет 1
Вариант №2
$test = 0.1 + 0.2; if (abs($test - 0.3) < 0.1) { echo '1'; } else { echo '0'; }
Данное выражение также даст нам положительный результат сравнения.