PHP. result of the subtraction of two floating point numbers
PHP浮点数的减法结果问题的原因在于浮点数在二进制中无法精确表达。它们都经过某种方式的四舍五入。问题在于为什么其中一个结果似乎被四舍五入到了两位小数,而另一个没有。答案在于浮点数的精度和准确度以及PHP用于打印它们的精度之间的差异。
浮点数由范围为[1, 2)的尾数(或称为有效数字)表示,通过乘以2的幂进行缩放(这就是浮点数中的“浮点”意味着什么)。数字的精度取决于尾数中的数字位数,而准确度取决于其中多少位实际上是正确的。
当在PHP中使用echo
打印浮点数时,它们首先会使用precision
配置设置进行转换为字符串,该设置默认为14。要了解实际情况,必须使用更大的精度打印数字。
下面的代码示例展示了实际发生的情况:
$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位精度打印时几乎不会被注意到。