(int)pow(n,m) 对于某些正整数 n,m 会是错误的吗?

Will (int)pow(n,m) be wrong for some positive integers n,m?

假设nm是正整数,nm在整数范围内,(int)pow(n,m)会给出答案有误?

我已经为 m=2 尝试了很多 n 并且到目前为止还没有得到任何错误的答案。

int 有 64 位且 double 也有 64 位的平台上,这可能无法作为 double([=13= 的参数和结果) ]) 没有足够的尾数来准确表示每个 64 位整数。在 int 具有 32 位且 double 是 64 位 IEEE 754 浮点类型的普通平台上,您的假设是正确的。

这取决于您的整数和双精度数的大小。

有了一个 32 位整数和一个 64 位 IEEE 754 双精度数,那么它将为您提供所有可能整数的正确答案。

一个 IEEE 754 binary64 浮点数(这是大多数现代机器上双精度的通常表示)可以精确表示所有整数 [0,2^53]。

一些实现在任何情况下都将 pow(x,y) 计算为 exp(y*log(x)),而其他实现对整数指数使用平方乘幂。

glibc for example has 'C' implementations,以及具有查找表、多项式近似值等的特定于平台的实现。许多 Sun/BSD 导数似乎将积分指数作为特例处理。

更重要的是,IEEE-754 不需要它。它也没有指定结果所需的准确性。 glibc documents 其最大 ulp 错误,尽管此页面可能不是最新的。

总而言之,不要假设一个精确的整数结果,即使pow(n,m)有一个精确的浮点表示。

C标准对浮点运算的精度没有任何要求。准确性是实现定义的,这意味着需要实现来记录它。但是,实现留下了重要的 "out":(§5.2.4.2.2 第 6 段,强调已添加。)

The accuracy of the floating-point operations (+, -, *, /) and of the library functions in <math.h> and <complex.h> that return floating-point results is implementation-defined, as is the accuracy of the conversion between floating-point internal representations and string representations performed by the library functions in <stdio.h>, <stdlib.h>, and <wchar.h>. The implementation may state that the accuracy is unknown.

事实上,gcc 通过指定 the accuracy is unknown 来利用这一点。尽管如此,glibc 计算的准确性非常好,即使不能保证。

已知 MS libc 实现偶尔会为带有整数参数的 pow 函数产生 1ULP 错误,如果 pow 操作的结果被简单地截断为一个 int。 (我在 Visual Studio 文档中找不到任何关于浮点精度的规范,但我相信下面的 SO 问题列表提供了我断言的证据。)

在 x86 架构上,大多数实现都会尝试实现 IEEE 754,因为本机浮点表示符合。然而,在 2008 年修订版之前,IEEE-754 只需要 +-*/sqrt 的正确舍入结果。自修订以来,it recommends 许多其他函数 return 正确舍入结果,但所有这些建议都是可选的,很少有数学库实现所有这些。

如果您真的想使用 pow 来计算整数的整数次方,建议(并且容易)使用 lround(pow(n, m)) 而不是 (long)(pow(n, m)),这将对结果进行四舍五入到最接近的整数,而不是乐观地依赖误差为正。如果 pow 在 1ULP 之内,那应该给出最多 252(使用 IEEE-754 双精度)的结果的正确整数值。在 252 和 253 之间,1ULP 误差为 0.5,有时会四舍五入为错误的整数。超过 253 并非所有整数都可以表示为双精度。

SO 实际上充满了由这个特定问题引起的问题。参见:

  • Reversing a five digit number with POW function in C
  • C's pow() function as per header file <math.h> not working properly
  • Strange behaviour of the pow function
  • Why am I getting unexpected output when using floor with pow?
  • Why pow(10,5) = 9,999 in C++
  • return value of pow() gets rounded down if assigned to an integer (found by Lưu Vĩnh Phúc)
  • wrong output by power function - C(也)

毫无疑问还有更多。