4

我只是“修复”了以下 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(). 它是什么?

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

4

2 回答 2

6

重点:

初始数据类型是 float64。

乘以 100 后,它仍然是一个浮点数。

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

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

因此你的问题。


作为旁注:

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

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

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

例 1:

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

例 2:

0  == false // true
0 === false // false
于 2012-08-20T15:58:34.203 回答
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 在他的回答中可能是正确的,但似乎这些“近似”浮点数(具有无限数量的 99999)存在于浮点算术单元的深处,并且仅在某些非常特殊的情况下影响 PHP 级别的计算案例。

于 2012-08-20T17:18:20.990 回答