对于某些正整数n,m,will(int)pow(n,m)是错误的吗?
假设n
和m
是正整数,并且n m在整数范围内,那么(int)pow(n,m)
给出错误的答案吗?
我为m=2
尝试了很多n
,到目前为止还没有得到任何错误的答案。
C标准对浮点运算的精度没有任何要求。 准确性是实现定义的 ,这意味着需要实现来记录它。 然而,实现留下了重要的“结果”:(第5.2.4.2.2段第6段,重点增加。)
返回浮点结果的
和
中的浮点运算(
+
,-
,*
,/
)和库函数的准确性是实现定义的,精度也是由,
和
的库函数执行的浮点内部表示和字符串表示之间的转换。 实施可能表明准确性未知。
事实上,gcc通过指定准确性未知来利用这一点。 尽管如此,即使没有保证,glibc计算的准确性也相当不错。
已知MS libc实现偶尔会为具有整数参数的pow
函数产生1ULP的错误,如果将pow
操作的结果简单地截断为int
则会导致错误的值。 (我在Visual Studio文档中找不到关于浮点精度的任何规范,但我相信下面的SO问题列表提供了我断言的证据。)
在x86体系结构中,大多数实现都尝试实现IEEE 754,因为本机浮点表示符合。 但是,在2008年修订版之前,IEEE-754只需要+
, -
, *
, /
和sqrt
正确舍入结果。 自修订以来, 它建议许多其他函数返回正确的舍入结果,但所有这些建议都是可选的,并且很少有数学库实现所有这些。
如果你真的想用pow
来计算整数的整数幂,那么建议(并且很容易)使用lround(pow(n, m))
而不是(long)(pow(n, m))
,这将绕过得到最接近的整数,而不是乐观地依赖于误差为正。 如果pow
在1ULP之内,那么应该为结果提供正确的整数值,最多为2 52 (使用IEEE-754双倍)。 在2 52和2 53之间 ,1ULP误差为0.5,有时会舍入到错误的整数。 超过2 53并非所有整数都可以表示为双精度。
因此,这个问题实际上充满了问题。 看到:
- 使用C中的POW函数反转五位数字
- C的pow()函数根据头文件
无法正常工作 - powfunction的奇怪行为
- 为什么在使用带有电源的地板时会出现意外的输出?
- 为什么在C ++中pow(10,5)= 9,999
- 如果赋值为整数,则将pow()的返回值向下舍入 (由LưuVĩnhPhúc找到)
- 电源function错误输出 – C (也)
毫无疑问,还有更多。
一些实现在任何情况下都将pow(x,y)
评估为exp(y*log(x))
,而其他实现则使用平方乘法为积分指数。
例如, glibc具有’C’ 实现 ,以及具有查找表,多项式近似等的特定于平台的实现。许多Sun / BSD派生物似乎作为特殊情况处理整数指数。
更重要的是,IEEE-754不要求它。 它也没有规定结果所要求的准确性。 glibc 记录了它的最大ulp错误,尽管这个页面可能不是最新的。
总之,即使pow(n,m)
具有精确的浮点表示, 也不要假设精确的积分结果 。
在int
有64位且double
也有64位的平台上,这可能不能用作double
( pow()
的参数和结果没有足够的尾数来精确表示每个64位整数。 在一个普通的平台上, int
有32位, double
是64位IEEE 754浮点类型,你的假设是正确的。
这取决于整数和双精度的大小。
使用32位整数和64位IEEE 754 double,它将为所有可能的整数提供正确的答案。
IEEE 754 binary64浮点数(在大多数现代机器上通常表示双精度数)可以精确地表示所有整数[0,2 ^ 53]。