首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >PHP错误或者我哪里错了?

PHP错误或者我哪里错了?
EN

Stack Overflow用户
提问于 2018-11-29 22:35:31
回答 3查看 138关注 0票数 2
代码语言:javascript
运行
复制
function dec2sat( $decimal )
{
    return $decimal * (10**8);
}

echo dec2sat(0.06999206); // result: 6999206 (float type)

var_dump(dec2sat(0.06999206) >= 6999206); // result: FALSE

请大家给我解释一下为什么var_dump(dec2sat(0.06999206) >= 6999206);返回FALSE?

测试: PHP 7.2.12、PHP 7.1.22、PHP 5.6.38

EN

回答 3

Stack Overflow用户

发布于 2018-11-29 22:47:36

您正在尝试比较float和integer。在这种情况下,PHP需要显式地将浮点数转换为整数。当您运行以下代码时:

代码语言:javascript
运行
复制
var_dump((int)dec2sat(0.06999206)); // 6999205

你会得到6999205,显然比6999206要小。

当你尝试比较字符串和整型时也是一样的。这将输出true:

代码语言:javascript
运行
复制
var_dump('string' == 0); // true

这是您需要始终比较类型和值的方法,以避免这种行为。下面的代码将输出true,它不是一些漂亮的解决方案,但它是有效的。也可以尝试其他情况。

代码语言:javascript
运行
复制
var_dump(round(dec2sat(0.06999206), 0) >= 6999206); // true

为什么会发生这种情况:

浮点数的精度是有限的。虽然它取决于系统,但PHP通常使用IEEE 754双精度格式,由于舍入在1.11e-16的数量级,该格式将产生最大相对误差。非初等算术运算可能会产生更大的误差,当然,当几个运算组合在一起时,必须考虑误差传播。

此外,在基数10中可以精确表示为浮点数的有理数,如0.1或0.7,在内部使用的基数2中没有精确的浮点数表示,无论尾数的大小如何。因此,它们不能在没有小的精度损失的情况下转换成它们的内部二进制对应物。这可能会导致混乱的结果:例如,floor((0.1+0.7)*10)通常会返回7,而不是预期的8,因为内部表示将类似于7.9999999999999991118...

在我们的例子中,当你去掉小数点后面的所有隐藏数字时,你会得到下一个结果:

代码语言:javascript
运行
复制
var_dump(number_format(dec2sat(0.06999206), 30, '.', '')); // 6999205.999999999068677425384521484375
var_dump(number_format(dec2sat(0.06999206), 9, '.', '')); // 6999205.999999999
var_dump(number_format(dec2sat(0.06999206), 8, '.', '')); // 6999206.00000000

结论:

切勿将浮点数结果信任到最后一位数,也不要直接比较浮点数是否相等。如果需要更高的精度,可以使用任意精度的数学函数和gmp函数。

要么将返回值转换为整数,要么将其向上舍入到8位小数。

票数 2
EN

Stack Overflow用户

发布于 2018-11-29 22:46:30

代码语言:javascript
运行
复制
function dec2sat($decimal)
{
    return $decimal * (10 ** 8) . '';
}
票数 0
EN

Stack Overflow用户

发布于 2018-11-30 13:05:13

我想说的第一件事是:非常感谢您花时间寻找我的问题的解决方案。我的问题的主要目的不是找出解决方案,我需要知道导致上述意外结果的原因,因为这有助于我避免以后重复。

在看了Aleksandar Raki的答案后,我在ć中做了一些关于浮点型的搜索,现在,我想我已经找到了导致var_dump(dec2sat(0.06999206) >= 6999206);返回FALSE的原因。你可以在这里阅读:Warning: Floating point precision

我认为数字0.06999206不是真正的0.06999206,它在内部存储时可能是0.069992059999...,函数dec2sat(0.06999206)的结果是6999205.999...这就是为什么Aleksandar Rakić的解决方案返回预期结果的原因。

以下是编辑后的dec2sat()

代码语言:javascript
运行
复制
function dec2sat( $decimal )
{
     return intval(round( $decimal * (10**8) )); // $decimal always has decimal value <= 8 digits
}

函数dec2sat()的主要目标是将floating point number转换为int,以避免在我的应用程序中直接处理floating point number

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53541387

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档