【问题标题】:Why is PHP float division and POW giving wrong results and unexpected results?为什么 PHP 浮点除法和 POW 会给出错误的结果和意外的结果?
【发布时间】:2011-01-23 23:34:57
【问题描述】:

有谁知道为什么会发生这种情况以及是否可以解决。我正在比较 C 和 PHP 的结果,但 PHP 给了我不同的结果。

如果需要,我可以提供一些代码,但以前有人经历过吗?

PHP 代码

$tempnum = 1.0e - 5 * -44954; // substr($line1,53,6); $bstar = $tempnum / pow(10.0, 3); $bstar 在 PHP 中给了我 -0.00044954 但它应该是 -0.000450

C 代码

双倍温度 = 1.0e - 5 * -44954; 双 bstar = tempnum / pow(10.0, 3); printf bstar 给我 -0.000450

到目前为止,感谢您的回复,但是 PHP 是如何得出这个结论的...

$twopi = 6.28318530717958623; /* 2*Pi */ $xmnpda=1440; //1.44E3 ; /* 每天分钟 */ $temp = (($twopi/$xmnpda)/$xmnpda); $xndt2o = -0.000603; $xndt2o = $xndt2o * $temp; echo $xndt2o 在 PHP 中给了我 -1.8256568188E-9 但在 C 中它给了我 -0.000000

我不知道 PHP 中的所有内容。

【问题讨论】:

  • The accuracy of PHP float calculate 的可能副本以及该问题的数百个其他变体
  • 您现在应该提供代码。并告诉我们它们有何不同、结果如何以及您的期望。 (另外:PHP 是用 C 实现的,它可能在后台使用 C 双精度。)
  • 我们还需要看到等价的C。
  • 我已经提供了我正在使用的代码。
  • 你还没有完全 - C 代码不会编译。格式字符串很重要。

标签: php c math division pow


【解决方案1】:

有限精度浮点格式几乎总是有点不准确,这些不准确会相互叠加,并以意想不到的方式表现出来。通常,结果并没有那么大的错误,但唯一的问题是您没有预料到这些错误。有关一般说明,请阅读The Floating-Point Guide

也许与您的问题最相关:永远不应该期望计算序列在跨平台产生完全相同的结果,因为有许多因素可能导致执行不同的实际原始操作。 This paper explains it in great detail..

对您所看到的差异的更简单的解释可能是 PHP 代码在某处仅使用了 32 位浮点数,因为差异显示在小数点后 6/7 位左右,即 32 位浮点数的准确性结束。

【讨论】:

  • 但是 PHP 和 C 中的计算是相同的,PHP 是用 C 编写的,所以我希望得到相同的结果。
  • @Carl:好吧,你的期望是错误的。浮点运算经常发生这种情况。请看一下我链接到的论文。
  • 我的经验法则:永远不要相信浮点计算与你的生活;)所有浮点运算都是不准确的。这是将十进制数表示为二进制的固有限制。这会影响所有编程语言(不仅仅是 PHP 和 C),这只是在遇到此限制之前它们可以提供多少位的问题。浮点指南确实是一本很好的读物。
  • @azure_ardee:所有数字格式都不准确,因为它们都不能代表整数的整体,更不用说有理数或实数了。二进制浮点格式的问题在于它们在意想不到的方面不准确,主要与二进制和十进制表示之间的差异有关。
【解决方案2】:

如果您告诉printf 显示更多数字,等效的 C 代码会给出相同的结果:

printf("%.8f\n", bstar);

【讨论】:

  • @Carl,向我们展示您正在使用的 printf。如果您正在执行 %.8f 那么您将只显示小数点后的 8 位数字。计算结果是 * 10^-9 ,这需要在 printf 格式字符串中使用更多数字。
  • @Carl:这只是再次显示精度。试试printf("%g\n");
  • @Oli 好的,如果我这样做
     printf("xndt2o: %g\n", xndt2o);它给了我-0.00060251,经过我的计算,它给了我-1.82566e-009 
  • -0.00060251 在 php 中是相同的,但正如您所看到的 -1.82566e-009 在 PHP 中是不一样的,并且在 PHP 中进行了大约 500 行计算后,当代码为与C代码相同..
  • @Oli Charlesworth 我知道如何在 C 中使用它们,我使用 printf 的唯一原因是我可以将 C 结果与 PHP 进行比较。我希望我的代码在 PHP 而不是 C 中工作。所以无论我如何告诉 C 打印精度,最后,PHP 中的结果都是正确的。
【解决方案3】:

非常感谢你们的帮助。我想通了。

有时您需要在 PHP 中处理大数字。例如,有时 32 位标识符是不够的,您必须使用 BIGINT 64 位。

我已经写过关于 64 位整数在 PHP 中的混乱。但是,如果您使用的数字没有完全覆盖 64 位范围,那么浮点数可能会节省时间。诀窍在于 PHP 浮点数实际上是双精度数,即双精度 64 位数字。它们有 52 位尾数,可以精确存储高达 2^53-1 的整数值。因此,如果您使用最多 53 位,则可以使用浮点数。

但是,您应该注意一个转换警告。

浮点到字符串的转换不能跨系统和 PHP 版本移植。因此,如果您正在处理存储为浮点数的大量数字(尤其是在 32 位系统上,其中 32 位 int 溢出将隐式​​转换为浮点数)并得到奇怪的结果,请记住字符串转换可能会让您失望。另一方面,sprintf() 在修复 PHP 在数值处理中的“微妙之处”时始终是一个朋友:它可用于解决有符号和无符号 int 问题;它有助于浮点格式;永远是救世主。

References - MySQL Performance Blog

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-30
    • 2022-01-05
    • 2012-12-06
    • 2018-07-04
    相关资源
    最近更新 更多