PHP: математические вычисления и сравнения - PullRequest
0 голосов
/ 27 июля 2011

Я бы ожидал, что все приведенные ниже сравнения будут логическими (правда), но это не так. Кто-нибудь может объяснить это?

test.php

<?php

$f = 12;
$f += 5.95;
$f += 5.95;
$f += 5.95;

echo 'var_dump($f) = ';
var_dump($f);

echo 'var_dump($f == \'29.85\') = ';
var_dump($f == '29.85');

echo 'var_dump($f == 29.85) = ';
var_dump($f == 29.85);

echo 'var_dump($f == (float)\'29.85\') = ';
var_dump($f == (float)'29.85');

echo 'var_dump($f == \'29.85\') = ';
var_dump((string)$f == '29.85');

echo 'var_dump(round($f, 2) == \'29.85\') = ';
var_dump(round($f, 2) == '29.85');

$ php test.php

var_dump($f) = float(29.85)
var_dump($f == '29.85') = bool(false)
var_dump($f == 29.85) = bool(false)
var_dump($f == (float)'29.85') = bool(false)
var_dump($f == '29.85') = bool(true)
var_dump(round($f, 2) == '29.85') = bool(true)

$ php -v

PHP 5.2.14 (cli) (built: Jul 23 2010 15:23:00)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies
    with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans

Ответы [ 3 ]

5 голосов
/ 27 июля 2011

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

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

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

Страница документации PHP

1 голос
/ 27 июля 2011

Когда вы сравниваете значения в виде строк, обе стороны равны '29.85', поэтому вы получаете true. Пока все просто.

Сравнение по числовому значению ведет вас в страну двоичных представлений значений с плавающей запятой. Поскольку числа хранятся в base-2, любое действительное число, которое не , выражаемое в конечное двоичное расширение , не может точно быть представлено числом с плавающей запятой.

Другими словами, каждое число, которое не может быть записано как дробь целых чисел, где знаменатель является степенью 2, не может быть представлено таким образом. Это включает в себя 1/5 и 1/10 и 597/20 (что составляет 29,85).

Поскольку эти числа не могут быть точно представлены, результат операций с такими числами зависит от порядка операций и ошибок округления и усечения, и поэтому, например, .1 + .1 + .1 не совпадает с .3, и аналогичен для вашего вычисления.

0 голосов
/ 27 июля 2011

Как говорит @Shakti Singh, числа с плавающей точкой не сохраняются точно, поэтому я предполагаю, что $ f на самом деле хранится как что-то вроде 29.849999999999999 ..., поэтому не точно равно 29.85.

Такжеэта строка кода выглядит неправильно:

echo 'var_dump($f == \'29.85\') = ';
var_dump($f == 29.85);

Я предполагаю, что это должно быть:

echo 'var_dump($f == \'29.85\') = ';
var_dump($f == '29.85');
...