(int)pow(n,m) 对于某些正整数 n,m 会是错误的吗?
Will (int)pow(n,m) be wrong for some positive integers n,m?
假设n
和m
是正整数,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(也)
毫无疑问还有更多。
假设n
和m
是正整数,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(也)
毫无疑问还有更多。