c中浮点的精确表示

use*_*erv 5 c floating-point

void main()
{
    float a = 0.7;

    if (a < 0.7)
        printf("c");
    else
        printf("c++");
} 
Run Code Online (Sandbox Code Playgroud)

在上面的0.7问题中,将打印"c",但是对于0.8,将打印"c ++".为什么?

那么浮点数是如何用二进制形式表示的?

在某些地方,提到内部0.7将存储为0.699997,但0.8存储为0.8000011.为什么这样?

vic*_*tcu 12

基本上用浮点数你会得到32位编码

VALUE   = SIGN * MANTISSA * 2 ^ (128 - EXPONENT)
32-bits = 1-bit  23-bits               8-bits
Run Code Online (Sandbox Code Playgroud)

并存储为

MSB                    LSB
[SIGN][EXPONENT][MANTISSA]
Run Code Online (Sandbox Code Playgroud)

因为你只得到23位,这就是你可以存储的"精度".如果您试图表示在基数2中无理(或重复)的分数,则位序列将在第23位"舍入".

0.7 base 10是7/10,二进制是0b111/0b1010你得到:

0.1011001100110011001100110011001100110011001100110011... etc
Run Code Online (Sandbox Code Playgroud)

由于这种情况重复,因此在固定精度下无法准确表示它.同样适用于0.8,二进制是:

0.1100110011001100110011001100110011001100110011001101... etc
Run Code Online (Sandbox Code Playgroud)

要查看这些数字的固定精度值是什么,您必须以比特数"切断它们"并进行数学运算.唯一的技巧是你隐含的前导1并没有存储,所以你在技术上获得了额外的精度.由于舍入,最后一位将是1或0,具体取决于截断位的值.

因此,0.7的值实际上是11,744,051/2 ^ 24(无舍入效应)= 0.699999988,而0.8的值实际上是13,421,773/2 ^ 24(向上舍入)= 0.800000012.

这里的所有都是它的 :)


ues*_*esp 10

对此有一个很好的参考是每个计算机科学家应该知道的浮点运算.如果需要,可以使用更高精度类型(例如double)或二进制编码十进制(BCD)库来获得更好的浮点精度.