Округление в PHP - PullRequest
       71

Округление в PHP

3 голосов
/ 18 августа 2010
$a = ((0.1 + 0.7) * 10) == (int)((0.1 + 0.7) * 10);

PHP возвращает false.

Может кто-нибудь объяснить мне, почему это происходит?Первый возвращает 8, второй 7.

Ответы [ 7 ]

14 голосов
/ 18 августа 2010

Цитирование большого жирного красного предупреждения в Руководстве PHP по точности с плавающей запятой :

Обычно простые десятичные дроби, такие как 0.1 или 0.7 не могутпреобразованы во внутренние двоичные аналоги без малой потери точности.Это может привести к сбивающим с толку результатам: например, floor((0.1+0.7)*10) будет обычно возвращать 7 вместо ожидаемого 8, поскольку внутреннее представление будет выглядеть примерно так: 7.9.

Это связано сДело в том, что невозможно выразить некоторые дроби в десятичной записи с конечным числом цифр.Например, 1/3 в десятичной форме становится 0.3.

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

5 голосов
/ 18 августа 2010

Арифметика с плавающей точкой не является точной. Точно вместо 8.0 вы можете получить 7.999 ... который усекается до 7 при преобразовании в целое число.

echo number_format((0.1 + 0.7) * 10, 20);

Результат:

7.99999999999999911182
2 голосов
/ 18 августа 2010

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);
1 голос
/ 18 августа 2010

С Руководство по плавающей точке (щелкните для подробных объяснений):

Поскольку внутренне компьютеры используют формат (двоичная с плавающей точкой), который не может точно представлять числонапример, 0,1, 0,2 или 0,3 на всех .

Когда код скомпилирован или интерпретирован, ваш «0,1» уже округляется до ближайшего числа в этом формате, что приводит к небольшому округлениюошибка еще до того, как произойдет расчет.

1 голос
/ 18 августа 2010

Ответ Марка бьет по голове, но я думаю, что вместо приведения вам нужна круглая функция PHP:

http://php.net/manual/en/function.round.php

0 голосов
/ 18 августа 2010

Вы можете сделать сравнение следующим образом:

$a = round(((0.1 + 0.7) * 10), 1) == (int)round(((0.1 + 0.7) * 10), 1);
0 голосов
/ 18 августа 2010

Поскольку работа с числами с плавающей запятой не является точной на 100%, вероятно, перед приведением значения из выражения что-то вроде 7.9999 ...

...