PHP var_dump 不一致,浮点计算的楼层结果错误

对于这段代码:


$value = 200.1;

$denominator = 0.1;

echo "value: $value\n";

echo "denominator: $denominator\n";


$resultInt = ($value / $denominator);

echo "($value / $denominator) = ";

printf ("%f\n", $resultInt);


$resultInt = (int) ($value / $denominator);

echo "(int) ($value / $denominator) = ";

printf ("%f\n", $resultInt);


$resultInt = floor($value / $denominator);

echo "floor($value / $denominator) = ";

printf ("%f\n", $resultInt);


$resultInt = floor((int) ($value / $denominator));

echo "floor((int) ($value / $denominator)) = ";

printf ("%f\n", $resultInt);


$resultInt = floor((float) 2001);

echo "floor((float) 2001) = ";

printf ("%f\n", $resultInt);


$resultInt = round($value / $denominator, PHP_ROUND_HALF_DOWN);

echo "round($value / $denominator, PHP_ROUND_HALF_DOWN) = ";

printf ("%f\n", $resultInt);


$valueMul = $resultInt * $denominator;

if ($valueMul !== $value) {

    echo "they are not the same\n";

    var_dump($value);

    var_dump($valueMul);

}


$valueDiff = $value - $valueMul;

if ($valueDiff !== 0) {

    echo "valueDiff is not zero\n";

    var_dump($valueDiff);

}

我有这个结果:


value: 200.1

denominator: 0.1

(200.1 / 0.1) = 2001.000000

(int) (200.1 / 0.1) = 2000.000000

floor(200.1 / 0.1) = 2000.000000

floor((int) (200.1 / 0.1)) = 2000.000000

floor((float) 2001) = 2001.000000

round(200.1 / 0.1, PHP_ROUND_HALF_DOWN) = 2001.000000

they are not the same

float(200.1)

float(200.1)

valueDiff is not zero

float(-2.8421709430404E-14)

上述所有计算的预期结果是 2001,但在某些情况下它是 2000。


我知道由于计算机在二进制上运行,因此分数不会以小数形式存储在变量中。

但正如地板手册所述:

地板 -向下入分数

因此我期望得到与以下相同的结果:

round(200.1 / 0.1, PHP_ROUND_HALF_DOWN)

但 round 按预期返回 2001,而下限返回 2000(错误)。

你知道为什么吗?

我还发现这var_debug是不一致的:


大话西游666
浏览 71回答 1
1回答

慕斯王

您遇到了精度问题。在 PHP 中,您永远不应该相信浮点数的最后一位数字。从手册(浮点数)中,第二段甚至有关于您的特定测试数字的一点:浮点数的精度有限。虽然这取决于系统,但 PHP 通常使用 IEEE 754 双精度格式,由于按 1.11e-16 的顺序舍入,这将给出最大相对误差。非初等算术运算可能会产生较大的误差,当然,当多个运算复合时,必须考虑误差传播。此外,可以精确表示为以 10 为基数的浮点数的有理数(例如 0.1 或 0.7),没有精确表示为以 2 为基数的浮点数(无论尾数的大小如何,在内部使用)。因此,它们无法在不损失少量精度的情况下转换为内部二进制对应项。这可能会导致令人困惑的结果:例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期的 8,因为内部表示类似于 7.9999999999999991118...因此,永远不要相信浮点数结果到最后一位,也不要直接比较浮点数是否相等。如果需要更高的精度,可以使用任意精度数学函数和 gmp 函数。
打开App,查看更多内容
随时随地看视频慕课网APP