为什么floor(0.99999999999999999) = 1而floor(0.9999999999999999) = 0?

3

PHP中的floor函数表现得很奇怪。对于16个小数位,它会给出floor值,但增加1个小数位后就会四舍五入。

$int = 0.99999999999999999; 
echo floor($int); // returns 1 

$int = 0.9999999999999999; 
echo floor($int); // returns 0

$int = 0.99999999999999994; 
echo floor($int); // returns 0
  1. 有没有明确/解释在什么情况下它会给出“round”值?
  2. 是否有任何函数在十进制中有多少个9时都会给出0

4
因为浮点数的精度问题,详见https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems。 - Mark Baker
2个回答

14

向下取整的不是 floor 函数,而是浮点数运算。

这行代码:

echo 0.99999999999999999;

输出 1 (示例),因为0.99999999999999999 的精度对于(64位?)浮点数来说太高了,所以取最接近的可能值,恰好是1
0.99999999999999994 也太精确无法准确表示,但是在这里,最接近可表示的值恰好是0.9999999999999999

  1. 是否有定义/解释何时给出“四舍五入”的值?

这很复杂,但数字几乎总是四舍五入。
我认为没有“从什么时候开始进行值逼近”的定义,但这是根据IEEE 754浮点标准中的定义推导出来的数学属性。
为了安全起见,请假设一切都是近似的。

  1. 是否有任何函数可以在十进制数中有多少个9时给出0?

没有。问题是,在PHP中,0.999999999999999991 完全相同。
它们由完全相同的比特序列表示,所以无法区分它们。

有一些解决方案可以处理更大精度的小数,但这需要进行一些重大的代码更改。
可能对你感兴趣:

在PHP中使用大数

请注意,尽管您可以获得任意精度,但您永远不会获得无限精度,因为那将需要无限的存储空间。

还请注意,如果您确实正在处理无限精度,0.999...(继续下去)将真正地(即,在数学上证明的)等于1,详见此维基百科文章


2
了解它更好的两个有用链接:http://www.binaryconvert.com/result_double.html?decimal=048046057057057057057057057057057057057057057057057057057和http://www.binaryconvert.com/result_double.html?decimal=048046057057057057057057057057057057057057057057057057057 - Blackhole
实际上,这是双精度64位浮点数,可以精确到约15-16个数字。单精度只能精确到约7个数字。 - phuclv

0
$float_14_digits = 0.99999999999999;
echo $float_14_digits; // prints 0.99999999999999
echo floor($float_14_digits); // prints 0

$float_15_digits = 0.999999999999999;
echo $float_15_digits; // prints 1
echo floor($float_15_digits); // prints 1
exit;

在我的开发机器上,这种行为发生在数字“15”而不是像你的“17”。PHP会将浮点数中的最后一位四舍五入。你的floor()函数与此行为无关。


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