C 语言数的表示(二)

纯理论记录 C 语言是如何表示数值的,原理向,仅记录备忘。

十进制与二进制的转换

先记公式,任意一个二进制浮点数 V 可以表示成下面的形式:

V = (-1)s × M × 2E

  1. (-1)^s 表示符号位,当 s = 0 时,V 为正数,当 s = 1 时,V 为负数。

  2. M 表示有效数字,大于等于 1,小于 2。

  3. 2^E 表示指数位。

举例说明,十进制的 5.0,写成二进制是 101.0,相当于 1.01 × 2^2,那么,s = 0,M = 1.01,E = 2。

  • 32 位浮点数,最高 1 位是符号位 S,接着 8 位是指数 E,剩下 23 位为有效数字 M。
  • 64 位浮点数,最高 1 位是符号位 S,接着 11 位是指数 E,剩下 52 位为有效数字 M。

IEEE 754 对有效数字 M 和指数 E 还有一些特别的规定:

对于有效数字 M

1 ≤ M < 2,也就是说 M 可以写成 1.XXXX 的形式,其中 XXXX 表示小数部分。

在计算机内部保存 M 时,默认这个数的第一位总是 1,因此可以被舍去,只保存后面的 XXXX 部分。比如保存 1.01 的时候,只保存 01,等到读取的时候,再把第一位的 1 加上去。这样的目的,是节省 1 位有效数字。

以 32 位浮点数为例,留给 M 只有 23 位,将第 1 位舍去以后,等于可以保存 24 位有效数字。

对于指数 E

首先,E 为一个无符号数 unsigned int,如果 E 为 8 位,它的取值范围为 [0, 255];如果 E 为 11 位,它的取值范围为 [0, 2047]

但是,我们知道,科学计数法中 E 是可以出负数的,所以 IEEE 754 规定,E 的真实值必须再减去一个中间数,对于 8 位的 E,这个中间数是 127,对于 11 位的 E,这个中间数是 1023。

E 减去中间数得到的值即为指数阶码值(exponent bias),是指浮点数表示法中的指数域的编码值为实际值加上某个固定值,IEEE 754 规定该固定值为 2^(e-1) - 1,其中 e 为存储指数的比特的长度。

比如 2^10 的 E 是 10,保存的成 32 位的浮点数时,必须保存成 10 + 127 = 137,即 10001001

采用指数的实际值加上固定阶码值的办法表示浮点数的指数,好处是可以用长度为 e 个比特的无符号数表示所有的指数取值,这使得两个浮点数的指数大小的比较更为容易,实际上可以按照字典序比较两个浮点数的大小,这种移码表示指数部分,中文称为阶码。

以单精度型阶码表示示例如下:

例 1

如果我们要表示 0,则有 0 + 127 = 127,二进制表示为:0000 0000 + 0111 1111 = 0111 1111

例 2

如果我们要表示 1,则有 1 + 127 = 128,二进制表示为:0000 0001 + 0111 1111 = 1000 0000

例 3

如果我们要表示 2,则有 2 + 127 = 129,二进制表示为:0000 0010 + 0111 1111 = 1000 0001

例 4

如果我们要表示 128,则有 128 + 127 = 255,二进制表示为:1000 0000 + 0111 1111 = 1111 1111

移码 128 即为 8 位二进制移位存储表示的最大正数。

我们再来看一下负数:

例 5

如果我们要表示 -1,则有 -1 + 127 = 126,二进制表示为:1111 1111 + 0111 1111 = 0111 1110

然后,指数 E 还分三种情况:

  1. E 不全为 0 或不全为 1 时,浮点数就采用上面的规则表示,即指数 E 的计算值减去 127(或 1023),得到真实值,再将有效数字 M 前加上第一位的 1。

  2. E 全为 0 时,浮点数的指数 E 等于 1 - 127(1-1023),有效数字 M 不再加上第一位的 1,而是还原为 0.XXXX 的小数,这样作是为了表示 ±0,以及接近 0 的很小的数值。

  3. E 全为 1 时,如果有效数字 M 全为 0,表示 ± 无穷大(正负取决于符号 s);如果有效数字 M 不全为 0,表示这个数不是一个数 (NaN)。


C 语言数的表示(二)
https://ywmy.xyz/2019/03/04/C语言数的表示(二)/
作者
ian
发布于
2019年3月4日
许可协议