C中的Double等于0问题

mbr*_*ove 9 c floating-point logarithm

我正在实现一个算法来计算C中的自然日志.

double taylor_ln(int z) {
    double sum = 0.0;
    double tmp = 1.0;

    int i = 1;
    while(tmp != 0.0) {
        tmp = (1.0 / i) * (pow(((z - 1.0) / (z + 1.0)), i));
        printf("(1.0 / %d) * (pow(((%d - 1.0) / (%d + 1.0)), %d)) = %f\n", i, z, z, i, tmp);
        sum += tmp;
        i += 2;
    }

    return sum * 2;
}
Run Code Online (Sandbox Code Playgroud)

如print语句所示,tmp最终确实等于0.0,但是循环继续.可能是什么导致了这个?

我在Fedora 14 amd64上并编译:

clang -lm -o taylor_ln taylor_ln.c
Run Code Online (Sandbox Code Playgroud)

例:

$ ./taylor_ln 2
(1.0 / 1) * (pow(((2 - 1.0) / (2 + 1.0)), 1)) = 0.333333
(1.0 / 3) * (pow(((2 - 1.0) / (2 + 1.0)), 3)) = 0.012346
(1.0 / 5) * (pow(((2 - 1.0) / (2 + 1.0)), 5)) = 0.000823
(1.0 / 7) * (pow(((2 - 1.0) / (2 + 1.0)), 7)) = 0.000065
(1.0 / 9) * (pow(((2 - 1.0) / (2 + 1.0)), 9)) = 0.000006
(1.0 / 11) * (pow(((2 - 1.0) / (2 + 1.0)), 11)) = 0.000001
(1.0 / 13) * (pow(((2 - 1.0) / (2 + 1.0)), 13)) = 0.000000
(1.0 / 15) * (pow(((2 - 1.0) / (2 + 1.0)), 15)) = 0.000000
(1.0 / 17) * (pow(((2 - 1.0) / (2 + 1.0)), 17)) = 0.000000
(1.0 / 19) * (pow(((2 - 1.0) / (2 + 1.0)), 19)) = 0.000000
(1.0 / 21) * (pow(((2 - 1.0) / (2 + 1.0)), 21)) = 0.000000
and so on...
Run Code Online (Sandbox Code Playgroud)

Mar*_*iot 10

浮点比较是精确的,所以10^-10不一样0.0.

基本上,你应该比较一些可容忍的差异,比如10^-7根据你写出的小数位数,可以这样做:

while(fabs(tmp) > 10e-7)
Run Code Online (Sandbox Code Playgroud)

  • 这是必须的链接:[每个计算机科学家应该知道的关于浮点算术的内容](http://citeseer.ist.psu.edu/viewdoc/download;jsessionid=86013D0FEFFA6CD1A626176C5D4EF9E2?doi=10.1.1.102.244&rep=rep1&type= PDF) (6认同)