C 为什么可以';我用pow函数重现浮点问题吗?

C 为什么可以';我用pow函数重现浮点问题吗?,c,floating-point,pow,C,Floating Point,Pow,我最近写了一些类似的代码: //计算a^b 无符号整数结果=1; for(无符号整数i=0;i

我最近写了一些类似的代码:

//计算a^b
无符号整数结果=1;
for(无符号整数i=0;i
我从
math.h
中得到了我应该使用
pow
的评论,我已经准备好指出浮点精度问题,因为
pow
返回一个
双精度。我甚至找到了一个能说明问题的例子。除了当我试着从另一个问题运行代码时,它“工作”很好(即没有1个问题)

以下是我一直在测试的代码:

#包括
#包括
int main()
{
无符号整数a=10;
无符号整数结果;

for(unsigned int b=1;b
pow
具有
double
参数和返回值()。
double
具有53位有效位精度()。另一方面,示例中的最大值为100000000,有30位,因此完全适合53位


更新:玩了之后,编译器甚至可以优化所有的计算,比如在您的示例中
a
,所有
b
值在编译时都是已知的,例如
clang
v9.0。使用
-O3
选项只打印常量(和
gcc
msvc
调用
pow

这取决于实现

链接问题中使用的实现显然使用超越函数来实现
pow()
,即使参数是精确整数。因此,它会产生舍入错误,因此结果有时略低于实际整数结果


您使用的实现显然是检查参数是否有零分数。在这种情况下,它使用一种算法来生成精确的整数结果(可以通过移动尾数和一些额外的乘法来完成)。只要结果在
double
的精度范围内,你就会得到一个将转换回精确整数的浮点。

我想你只是幸运了,所有的错误都是正向的,而不是负向的。因此结果就像
100000.00001
而不是
9999999.99999
。但它可能会我走了另一条路。谁告诉你使用
pow
进行整数计算是错误的。但是你的幂函数可以改进。@Barmar我不认为是这样的。我用许多其他值测试了它,如果我用
printf
打印出双精度的100位小数点,它都是零。一个实现on可以自由地将整型参数视为特例。但这不是必须的。您使用了一个实现进行了测试。在您获得关于产生整型参数精确结果的现代实现百分比的适当统计数据之前,您只需要再测试99个。@user3386109标准是否真的这么说?那么为什么
pow(10,一)==99
当链接问题中的
i==2
时?我认为大小无关紧要。我认为更多的是因为十进制浮点数不能用二进制格式准确表示。我可以找到其他几个SO问题,其中人们对小整数有同样的问题。@jnrbsn一些十进制分数无法精确表示,但可以表示整数。@Barmar:链接问题中的
pow
pow(10,2)返回的值不是100
因为它不是
pow
的良好实现。它与
3.*4相同。
返回的值不是12。我们不会说您得到11.9999…5是因为浮点错误;我们会说有人做得不好。@EricPostChil区别在于,浮点mul有硬件指令T乘法,因此没有人会想到使用对数来实现乘法。大多数机器中都没有求幂指令,因此实现者必须决定一种算法,并且对所有运算都使用对数是一个简单的选择。当求幂运算有一个精确的结果时,舍入错误的原因并不是因为使用了dental函数,但事实上实现不好。基本上每个
pow
实现都必须使用超越函数。但是,例如,macOS
pow
函数中的误差小于一个ULP。当数学结果可表示时,唯一具有误差小于n一个ULP是数学结果,所以没有错误。@EricPostChil我认为它没有必要总是使用超越函数,这是我的观点。它可以检测到两个参数都没有分数,并切换到一个简单的循环。
$ gcc -O3 -std=c99 -Wall -Wextra -Werror -Wpedantic -pedantic-errors -o pow_test pow_test.c -lm
$ ./pow_test
10
100
1000
10000
100000
1000000
10000000
100000000
1000000000