【问题标题】:What else does round() do besides rounding a number?除了对数字进行四舍五入之外,round() 还能做什么?
【发布时间】:2012-08-15 23:26:37
【问题描述】:

我刚刚“修复”了以下 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() 的工作方式不同。这是什么?

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

【问题讨论】:

  • "浮点数的精度有限。虽然它取决于系统,但 PHP 通常使用 IEEE 754 双精度格式,由于四舍五入,它会给出最大的相对误差,大约为 1.11e- 16. 非初等算术运算可能会产生较大的误差,当然,当多个运算复合时,必须考虑误差传播。”

标签: php floating-point arithmetic-expressions


【解决方案1】:

言归正传:

初始数据类型为 float64。

乘以 100 后仍然是浮点数。

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

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

因此你的问题。


附带说明:

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

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

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

例 1:

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

例 2:

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

【讨论】:

  • 我明白了。我知道存在这些问题,但我并没有准备好让它们在调试器中不可见。你是怎么知道确切值的?
  • 我没有我只是提供一个例子。你可以计算一个精确的值,但看看什么底数/尾数/指数组合会产生大约。 109109。但这很可能是许多不同的值组合。
【解决方案2】:

也许没那么简单……

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 级别的计算在一些非常特殊的情况下。

【讨论】:

  • 浮点运算意味着整数值增加时小数精度降低,整数值减小时小数精度增加。
  • 因此总体而言,较小的精度出现在 1000s 区域而不是 0.1 区域是可以预期的。
猜你喜欢
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 2013-04-07
  • 2021-04-05
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
相关资源
最近更新 更多