IEEE 754:它究竟是如何工作的?

为什么以下代码的行为与C中的行为相同?

float x = 2147483647; //2^31 printf("%f\n", x); //Outputs 2147483648 

这是我的思考过程:

 2147483647 = 0 1001 1101 1111 1111 1111 1111 1111 111 (0.11111111111111111111111)base2 = (1-(0.5)^23)base10 => (1.11111111111111111111111)base2 = (1 + 1-(0.5)^23)base10 = (1.99999988)base10 

因此,要将IEEE 754表示法转换回小数: 1.99999988 * 2^30 = 2147483520

所以从技术上讲,C程序必须打印出2147483520,对吗?

要表示的值将是2147483647.可以用这种方式表示的下两个值是2147483520和2147483648。

由于后者更接近无法代表的“理想状态”,因此使用它:在浮点数中,值得到舍入而不是截断。

该标准可在此处获得 。 您可能不得不购买它,因为IEEE(以及其他类似组织)主要通过销售标准来赚钱,以支付他们组装,游说接受和提高标准质量的成本。

这些位只意味着有人指定它们

“当我用一个词时,”Humpty Dumpty用一种轻蔑的语气说道,“这意味着我选择它的意思 – 既不多也不少。” “问题是,”爱丽丝说,“你是否可以说出很多不同的词语。” “问题是,”Humpty Dumpty说,“这是主人 – 这就是全部。” (通过镜子,第6章)

在这种情况下,IEEE已经确定了比特的含义,并且printf标志%f打印出正确的相应人类表示的原因是由于该标志也遵循相同的标准。

有时您可以设法将位转换为另一种数据类型(如int)并打印出这些位的“其他”表示。 C会捕获很多正常的数字促销,但你可以混淆它,通常是在将错误类型的指针分配给正确的地址(并解除引用它们)的帮助下。

请注意,当您手动进行数学运算时,实际硬件并不能保证完全按照您的方式进行数学运算。 使用整数数学,表示中的准确度要高得多,但对于浮点数学,如何舍入数字会使输出产生很大的差异。 这甚至没有提到有时被烧入系统的浮点错误(幸好不经常)。

浮点格式通常采用“标准化forms”,其中尾数的最高位始终为1.因为它始终为1,所以您不需要用一点来存储它。 因此,在解码这样的数字表示时,您需要在顶部添加1。

 2147483647 = 2^31 - 1 = +1 * 2^30 * 1.1111 1111 1111 1111 1111 1111 1111 11 

以IEEE 754-1985单精度格式对此数字进行编码时,有效数字将正确舍入。 对于舍入模式舍入到最接近的偶数 (默认舍入模式),这意味着它被舍入。

舍入前:

 exponent = 30, significand = 1.1111 1111 1111 1111 1111 1111 1111 11 

将有效位数舍入到小数点后的23位数后:

 exponent = 30, significand = 10.0000 0000 0000 0000 0000 000 

正常化后:

 exponent = 31, significand = 1.0 

以单精度格式编码:

 1 | 10011110 | 00000000000000000000000