PHP:浮动数学和比较

时间:2011-07-27 12:38:14

标签: php casting comparison

我希望以下所有比较都是bool(true),但事实并非如此。 谁能解释一下呢?

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 个答案:

答案 0 :(得分:5)

  

浮点数的精度有限。虽然这取决于   在系统中,PHP通常使用IEEE 754双精度格式,   由于订单的舍入,这将产生最大的相对误差   1.11e-16。非基本算术运算可能会更大   错误,当然,必须考虑错误编程   几个操作复杂化。

     

此外,有理数的数字可以完全表示为   基数10中的浮点数,如0.1或0.7,没有   精确表示为基数2中的浮点数,即   内部使用,无论尾数的大小。因此,他们   没有a就无法转换成它们的内部二进制对应物   精度损失小。这可能导致令人困惑的结果:for   例如,floor((0.1 + 0.7)* 10)通常会返回7而不是   预期8,因为内部表示将是类似的   7.9999999999999991118 ....

     

所以永远不要将浮动数字结果信任到最后一位数字,永远不要   比较浮点数是否相等。

PHP documentation page

答案 1 :(得分:1)

当您将值作为字符串进行比较时,双方都是'29.85',因此您获得了true。到目前为止很容易。

通过数值比较,您将进入二进制浮点值表示的范围。由于数字存储在base-2中,因此有限二进制扩展可表达的任何实数都不能用浮点数精确表示

换句话说,不能将每个不能写为分母为2的幂的整数的数字表示。这包括1/5和1/10以及597/20(即29.85)。

由于无法准确表示这些数字,因此涉及此类数字的操作结果取决于操作的顺序以及舍入和截断错误,因此例如.1 + .1 + .1.3不同和,类似的计算。

答案 2 :(得分:0)

正如@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');