【发布时间】:2014-11-24 14:34:16
【问题描述】:
我依赖于sprintf('%0.1f', 2.25) === '2.3',但事实证明它来自2.2!
事实上它似乎是随机的:
php > for ($j=0;$j<=10;$j++) { printf( "%s -> %0.1f\n",$j+ 0.05, $j+0.05); }
0.05 -> 0.1 // Up, as expected
1.05 -> 1.1 // Up, as expected
2.05 -> 2.0 // Down!
3.05 -> 3.0 // Down!
4.05 -> 4.0 // Down!
5.05 -> 5.0 // Down!
6.05 -> 6.0 // Down!
7.05 -> 7.0 // Down!
8.05 -> 8.1 // Up, as expected
9.05 -> 9.1 // Up, as expected
我完全没有抓住重点吗?我觉得地毯从我身下被拉开,我在学校学到的一切都是错误的......!当然,四舍五入的功能应该始终如一地做到吗? (我注意到round($n, 1) 按预期工作。)
【问题讨论】:
-
因为 2.05 内部实际上是 2.0499999123423423423 或其他。你正在处理花车。准确性不是他们的强项。
-
Surely a function to round numbers should do it consistently?。如果它实际上是一个四舍五入的函数。但它不是 -sprintf — Return a formatted string,根据 php.net。 -
@MarcB 明白了。你怎么知道的?我的意思是你可以手动计算出浮点数的二进制表示,但是如何让 PHP 输出 2.049999123(或任何它)? - 只是为了兴趣!
-
en.wikipedia.org/wiki/Floating_point 和 en.wikipedia.org/wiki/Double_precision 也是不错的读物。我认为浮点数非常难……如果您在阅读完所有这些内容后没有真正理解它,请不要感到难过。但不足之处在于,其中一些二进制数字是重复数字,而另一些则不是。有点像您不能将分数 1/3 准确地写为没有无限位的小数,但 1/4 很容易。这些重复数字的截断,如果它们恰好发生在您想要四舍五入的位置,可能会导致令人惊讶的结果。