$a = ((0.1 + 0.7) * 10) == (int)((0.1 + 0.7) * 10);
PHP возвращает false.
Может кто-нибудь объяснить мне, почему это происходит?Первый возвращает 8, второй 7.
Цитирование большого жирного красного предупреждения в Руководстве PHP по точности с плавающей запятой :
Обычно простые десятичные дроби, такие как 0.1 или 0.7 не могутпреобразованы во внутренние двоичные аналоги без малой потери точности.Это может привести к сбивающим с толку результатам: например, floor((0.1+0.7)*10) будет обычно возвращать 7 вместо ожидаемого 8, поскольку внутреннее представление будет выглядеть примерно так: 7.9. Это связано сДело в том, что невозможно выразить некоторые дроби в десятичной записи с конечным числом цифр.Например, 1/3 в десятичной форме становится 0.3. Поэтому никогда не доверяйте результатам с плавающей запятой последней цифре и никогда не сравнивайте числа с плавающей запятой для равенства.Если необходима более высокая точность, доступны математические функции произвольной точности и gmp .
Обычно простые десятичные дроби, такие как 0.1 или 0.7 не могутпреобразованы во внутренние двоичные аналоги без малой потери точности.Это может привести к сбивающим с толку результатам: например, floor((0.1+0.7)*10) будет обычно возвращать 7 вместо ожидаемого 8, поскольку внутреннее представление будет выглядеть примерно так: 7.9.
0.1
0.7
floor((0.1+0.7)*10)
7
8
7.9
Это связано сДело в том, что невозможно выразить некоторые дроби в десятичной записи с конечным числом цифр.Например, 1/3 в десятичной форме становится 0.3.
1/3
0.3
Поэтому никогда не доверяйте результатам с плавающей запятой последней цифре и никогда не сравнивайте числа с плавающей запятой для равенства.Если необходима более высокая точность, доступны математические функции произвольной точности и gmp .
Арифметика с плавающей точкой не является точной. Точно вместо 8.0 вы можете получить 7.999 ... который усекается до 7 при преобразовании в целое число.
echo number_format((0.1 + 0.7) * 10, 20);
Результат:
7.99999999999999911182
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
EDIT
$a = ((0.1 + 0.7) * 10) == 8; var_dump($a); echo '<br />'; define('PRECISION', 1.0e-08); $a = (abs(((0.1 + 0.7) * 10) - 8) < PRECISION); var_dump($a);
С Руководство по плавающей точке (щелкните для подробных объяснений):
Поскольку внутренне компьютеры используют формат (двоичная с плавающей точкой), который не может точно представлять числонапример, 0,1, 0,2 или 0,3 на всех . Когда код скомпилирован или интерпретирован, ваш «0,1» уже округляется до ближайшего числа в этом формате, что приводит к небольшому округлениюошибка еще до того, как произойдет расчет.
Поскольку внутренне компьютеры используют формат (двоичная с плавающей точкой), который не может точно представлять числонапример, 0,1, 0,2 или 0,3 на всех .
Когда код скомпилирован или интерпретирован, ваш «0,1» уже округляется до ближайшего числа в этом формате, что приводит к небольшому округлениюошибка еще до того, как произойдет расчет.
Ответ Марка бьет по голове, но я думаю, что вместо приведения вам нужна круглая функция PHP:
http://php.net/manual/en/function.round.php
Вы можете сделать сравнение следующим образом:
$a = round(((0.1 + 0.7) * 10), 1) == (int)round(((0.1 + 0.7) * 10), 1);
Поскольку работа с числами с плавающей запятой не является точной на 100%, вероятно, перед приведением значения из выражения что-то вроде 7.9999 ...