我最近写了一些与此类似的代码:
// Calculate a ^ b
unsigned int result = 1;
for (unsigned int i = 0; i < b; i++) {
result *= a;
}
[我得到我应该使用pow
中的math.h
的注释,并且我已经准备好指出浮点精度问题,因为pow
返回了double
。我什至发现了一个existing Stack Overflow question来说明问题。除非我尝试从另一个问题运行代码,否则它“正常”运行(即no不按1的问题)。
这是我正在测试的代码:
#include <math.h>
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int result;
for (unsigned int b = 1; b <= 9; b++) {
result = (unsigned int)pow(a, b);
printf("%u\n", result);
}
return 0;
}
这是我编译和运行它的方式(在GCC版本7.4.0的Ubuntu 18.04.3上:
$ 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
那么(unsigned int)pow(a, b)
为什么起作用?我假设编译器在做一些魔术来防止正常的浮点问题?它在做什么,为什么?如果不是所有的编译器都这样做,那么鼓励这些问题的无知似乎是一个坏主意。并且,如果所有现代编译器do都这样做,这是否就不再是您要担心的问题了?
[我也看到人们建议使用(unsigned int)(pow(a, b) + 0.1)
之类的东西来避免偏离1的问题。与通过循环执行我的解决方案相比,这样做有什么优点/缺点?
pow
具有double
自变量(cppreference.com)。 double
具有52位有效精度(Wikipedia)。另一方面,您的值的最大值1000000000具有30位,因此非常适合,而不会降低52位的精度。