为什么不能用pow函数重现浮点问题?

问题描述 投票:0回答:1

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

// 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的问题。与通过循环执行我的解决方案相比,这样做有什么优点/缺点?

c floating-point pow
1个回答
2
投票

pow具有double自变量(cppreference.com)。 double具有52位有效精度(Wikipedia)。另一方面,您的值的最大值1000000000具有30位,因此非常适合,而不会降低52位的精度。

© www.soinside.com 2019 - 2024. All rights reserved.