Skip to content

Conversation

tangl163
Copy link
Contributor

@tangl163 tangl163 commented May 11, 2019

1. 整型转换为浮点型可能会导致误差

首先在 C 中,32 位的单精度浮点数表示如下

31  30           23 22                     0
--------------------------------------------
| s |   exponent   |      fractional       |
--------------------------------------------

1位符号位;8位指数位;23位小数位

更多关于浮点数的格式,请参考 IEEE_754

当将整数转换为浮点数时,由于浮点数的 Rounding,在某些情况下
会导致结果有些不同。对于 32 位的单精度浮点数,当整数 n > 2 ^ 24 时,就有可能发生 Rounding。考虑如下程序

#include <stdio.h>
#include <stdlib.h>

static void foo(long n);

int
main(int argc, char *argv[])
{
    long n;

    if (argc != 2) {
        printf("Usage: %s number\n", argv[0]);
        exit(0);
    }

    n = atol(argv[1]);

    foo(n);

    exit(0);
}

static void
foo(long n)
{
    long lval;
    float fval;

    fval = n;
    lval = fval;

    printf("%ld\n", lval);
    printf("%.0f\n", fval);
}

编译程序运行得到如下结果

paul@localhost:/tmp$ ./a.out 16777216
16777216
16777216
paul@localhost:/tmp$ ./a.out 16777217
16777216
16777216
paul@localhost:/tmp$ ./a.out 16777218
16777218
16777218
paul@localhost:/tmp$ ./a.out 16777219
16777220
16777220

有的值被 round-up,而有的值被 round-down

2. 浮点数的四则运算也可能会导致误差

同样的,浮点数在四则运算中也会发生 Rounding.

static void
foo(long n)
{
    int sec, msec, msec1;

    sec = n / 1000;
    msec = (((float)n / 1000) - sec) * 1000;
    msec1 = n % 1000;

    printf("sec: %d msec: %d\n", sec, msec);
    printf("sec: %d msec: %d\n", sec, msec1);
}

编译程序运行得到如下结果

paul@localhost:/tmp$ ./a.out 1001
sec: 1 msec: 1
sec: 1 msec: 1
paul@localhost:/tmp$ ./a.out 1002
sec: 1 msec: 1
sec: 1 msec: 2
paul@localhost:/tmp$ ./a.out 1003
sec: 1 msec: 3
sec: 1 msec: 3
paul@localhost:/tmp$ ./a.out 1004
sec: 1 msec: 3
sec: 1 msec: 4
paul@localhost:/tmp$ ./a.out 1005
sec: 1 msec: 4
sec: 1 msec: 5
paul@localhost:/tmp$ ./a.out 1006

总结

模运算更便宜,也不会因为浮点数的 Rounding 而产生误差。所以推荐使用摸运算

参考文献:

[1] What Every Computer Scientist Should Know About Floating-Point Arithmetic
[2] c11 Annex F

@matyhtf matyhtf merged commit cf4ac96 into swoole:master May 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants