PHP. 两个浮点数相减的结果

5
例如...
$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;
// result is:-1198.9699999988 not the -1198,97

但在这个例子中:
$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;
//Result is: 0.03

为什么这两个例子有差异?缺乏精度吗?

7
再次提醒:http://floating-point-gui.de/ - user557846
为什么这两个例子有差异? - Andrey K.
@AndreyK。查看这个链接:http://php.net/manual/zh/language.types.float.php!浮点数具有有限的精度。 - Rizier123
2个回答

5
您的代码中的数字都无法以二进制浮点数的形式精确表示,它们都被四舍五入了。问题在于为什么一个结果(看起来)被四舍五入到两位小数,而另一个没有。答案在于浮点数的精度准确性以及 PHP 用于打印它们的精度之间的差异。

浮点数由范围在[1, 2)内的有效数字(或尾数)表示,通过将其乘以二的幂进行缩放。(这就是浮点中“浮动”的含义)。数字的精度有效数字中的数字数量确定。其准确性取决于其中有多少位数字实际上是正确的。有关更多详细信息,请参见:浮点数在内存中如何存储?

当你在PHP中使用echo输出浮点数时,它们会首先使用precision配置设置转换为字符串,该设置默认为14。(在Zend/zend_operators.c中)
要查看实际发生的情况,您需要使用更大的精度打印数字:
$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;

printf ("\$aa: %.20G\n", $aa);
printf ("\$bb: %.20G\n", $bb);
printf ("\$ab: %.20G\n\n", $ab);

$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;

printf ("\$cc: %.20G\n", $cc);
printf ("\$dd: %.20G\n", $dd);
printf ("\$cd: %.20G\n", $cd);

输出:

$aa: 10694994.890000000596
$bb: 10696193.859999999404
$ab: -1198.9699999988079071

$cc: 0.89000000000000001332
$dd: 0.85999999999999998668
$cd: 0.030000000000000026645

初始数字精度约为16到17位。当你减去$aa-$bb时,前4位数字会互相抵消。结果(虽然仍然具有约16到17位的精度)现在只有大约12位是准确的。当使用14位精度打印结果时,这种较低的准确性就会显现出来。
另一个减法($cc-$dd)只失去了一位数字的准确性,在使用14位精度打印时不明显。

2
这应该适用于您:
(您必须对结果四舍五入!)
$aa = 10694994.89;
$bb = 10696193.86;
echo $ab = round($aa - $bb, 2);

很明显我可以四舍五入,但为什么这两个例子会有差异呢? - Andrey K.
1
请阅读我发布的链接,了解计算机如何处理浮点数。 - user557846

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接