除了舍入数字之外,round()还做了什么?

时间:2012-08-20 15:48:50

标签: php floating-point arithmetic-expressions

我刚刚修复了以下几行PHP中的错误:

        $value = 1091.09; // the failing test case
        $prop = sprintf('%013d', $value * 100);

添加以下行:

        $cents = $value * 100; // $cents is now 109109
        $cents = round($cents, 2); // $cents is still 109109
        $prop = sprintf('%013d', $cents);

前一个块的结果是"0000000109108",而第二个块的结果是"0000000109109",这是正确的。

请注意,我添加了两行,以便能够分别查看调试器中的每个步骤。如果我跳过第一行,它也有效,因此写道:

        $cents = round($value * 100, 2); // $cents is now 109109
        $prop = sprintf('%013d', $cents);

因此,显然,round()函数会对值产生不可见的因素,使其与sprintf()的工作方式不同。它是什么?

如果这是一种正确的语言,我可能会通过查看数据类型来了解。在这里,我甚至不知道它们是什么。

2 个答案:

答案 0 :(得分:6)

至关重点:

初始数据类型为float64。

在乘以100之后,它仍然是浮动的。

打印(使用echo / print_r / var_dump)该值不会打印绝对精确值(109108.9999999999999);它打印出近似浮点值109109,因为浮点数本身就是近似值而不是精确值。

使用sprintf将其作为int 打印会触发将类型转换为int,从而将109108.9999999999999的值截断为109108

因此你的问题。


作为旁注:

PHP支持的基本类型是使用处理程序变量和引用计数容器构造的。除此之外,他们是非常低级的东西。

没有理由认为它们比它们出现的“更复杂”。我开始考虑复杂的对象而不是标量数据类型。

另一个很大的混淆因素是(隐式)类型转换和所有类型转换规则(包括可以作为布尔值传递的所有内容)。

实施例1,:

  -1 == false // true
null == false // true
  -1 != null  // false

例2:

0  == false // true
0 === false // false

答案 1 :(得分:0)

它可能不那么简单......

php > $value = 1091.09; print sprintf('%f', $value);
1091.090000
php > $value = 1091.09; print sprintf('%f', $value*100);
109109.000000
php > $value = 1091.09; print sprintf('%f', (int)($value*100));
109108.000000

人们期望在前两个结果中看到所有这些'999999'。

此外:

php > $value = 0.09; print sprintf('%f', $value);
0.090000
php > $value = 0.09; print sprintf('%f', $value*100);
9.000000
php > $value = 0.09; print sprintf('%f', (int)($value*100));
9.000000

(NOTE: same result of 0.009 and 0.9)

底线,@ Mihai可能正好在his answer,但似乎这些“近似”浮点数(无限数量为99999)存在于浮点运算单元内部深处并影响PHP级别仅在某些非常特殊的情况下进行计算。