【问题标题】:pow numeric error in cc中的pow数字错误
【发布时间】:2015-10-19 08:45:36
【问题描述】:

我想知道数字错误发生在哪里,在哪一层。 让我用一个例子来解释:

int p = pow(5, 3);
printf("%d", p);

我已经在各种硬件和编译器(VS 和 GCC)上测试了这段代码,其中一些打印出 124 和一些 125。

  • 在相同的硬件 (OS) 上,我在不同的编译器(VS 和 GCC)中得到不同的结果。
  • 在不同的 HW(OS) 上,我在同一个编译器 (cc (GCC) 4.8.1) 中得到不同的结果。

AFAIK,pow 计算为 124.99999999 并被截断为 int,但是这个错误发生在哪里? 或者换句话说,修正发生在哪里(124.99->125)

是编译器-硬件交互吗?

//******已编辑:

这里还有一个可以玩的 sn-p(请留意 p=5、p=18、...):

#include <stdio.h>
#include <math.h>

int main(void) {
    int p;
    for (p = 1; p < 20; p++) {
        printf("\n%d %d %f %f", (int) pow(p, 3), (int) exp(3 * log(p)), pow(p, 3), exp(3 * log(p)));
    }
    return 0;
}

【问题讨论】:

  • 计算机上的浮点值是一件复杂的事情,对它们的运算结果取决于很多事情。例如,硬件支持(如果有)、不同软件(编译器、标准库)或硬件使用的舍入算法,以及许多其他东西。
  • 另外请注意,当使用常量表达式时,编译器通常会use builtin functions,因此您可能还想尝试使用-fno-builtin 看看这是否会影响结果。
  • 我相信不是,我刚刚使用 for 循环添加了一个 sn-p 并且发生了同样的事情。
  • 为什么要截断为int?你为什么使用带有整数指数的pow?这些才是真正要问的问题。
  • 没错,但正如我所说 - 我知道这不是最佳做法,我肯定不会提倡这样做。附带说明一下,当一名学生试图计算一个数字是否是阿姆斯特朗数字 (cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap04/arms.html) 时,这个问题就出现了。这是一个诚实的错误,尤其是对学生而言。

标签: c gcc precision pow


【解决方案1】:

(首先请注意,对于 IEEE754 双精度浮点类型,所有 可以精确表示高达 2 的 53 次方的整数。将整数 pow 不准确归咎于浮点精度通常是不正确的)。

pow(x, y) 通常在 C 中实现为exp(y * log(x))。因此,即使是非常小的整数情况,它也可以“关闭”。

对于较小的积分情况,我通常用手写的方式编写计算,而对于其他积分参数,我使用第 3 方库。尽管使用 for 循环的 DIY 解决方案很诱人,但可以针对此类解决方案可能无法利用的积分功能进行有效的优化。

至于观察到的不同结果,可能是一些使用 80 位浮点中介的平台。可能有些计算值高于 125,而其他计算值则低于 125。

【讨论】:

  • 好的,我明白了,而且我知道这不是最佳做法 (pow->int)。我也知道 pow 会产生舍入错误,但正如我在问题中所说,我不知道这个错误发生在哪里。
  • 对于那些寻求有效的 int pow 实现的人:stackoverflow.com/questions/101439/…
  • log(5) 是一个double无法准确表示。 exp(3 log (5)) 很可能不是是一个整数。
  • 试试这个代码:#include #include int main(void) { int p; for (p = 1; p
  • 我怀疑差异归结为 80 位中介。也许 C 标准库在平台上以不同的方式实现 pow。您可以调整各种编译器设置来更改前者。
猜你喜欢
  • 2023-03-31
  • 2022-10-24
  • 2012-06-02
  • 1970-01-01
  • 2016-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多