B 浮点数的计算机表示
“The answer to the ultimate question of life, the universe and everything is 42.”——The Hitchhiker’s Guide to the Galaxy
这里只对双精度,单精度和半精度浮点数进行说明,不涉及x87的80位扩展精度浮点数。这几种浮点数都是按照IEEE754标准里规定的方式进行存储的。
计算机表示浮点数,其实用的是科学计数法,惊不惊喜,意不意外?只不过是二进制的科学计数法。计算机中的一个浮点数包含三个部分,符号、指数和尾数。下面用单精度浮点数来说明这三个部分是怎么组合成一个32位实体的。
B.1 单精度浮点数
一个单精度浮点数在内存中大概是下面这个样子的(不考虑实际存储按照大段序或小端序。左边是高位,右边是低位)。
图 B.1: 单精度浮点数
所有的单精度浮点数分为三种,规格化的,非规格化的和特殊值。
B.1.1 规格化的单精度浮点数
大多数浮点数是规格化的。规格化的浮点数要求指数部分不为全零且不为全一。
符号位(s)表示浮点数的正负。0表示正数,1表示负数。
指数部分(e)表示一个有偏置的指数。非全零或全一的八位二进制可以表示从1到254,这里偏置是-127。所以指数部分的范围是-126到+127.
尾数部分(f)之所以称为“尾数”,是因为小数点前面的1并没有被表达在这一部分里面。根据科学计数法的定义,小数点前必须有且仅有一位,而且不是零。二进制中,这一位只能是1.于是我们通过这种方法相当于获得了额外的一位精度。
综上,规格化的浮点数表示的值可以写成
\[ value = (-1)^s \times (1 + f \times 2^{-23}) \times 2^{e-127} \]
或者 \[ value = (-1)^s \times 1.f_{22}f_{21}\cdot\cdot\cdot f_{0} \times 2^{e-127} \]
B.1.2 非规格化的单精度浮点数
指数位全部为0的时候浮点数称为非规格化的浮点数。这部分浮点数提供了0的表示方法。
这部分浮点数就不适用科学计数法了,表示方法类似于无符号整数。
\[ value = (-1)^s \times f \times 2^{-149} \]
或者
\[ value = (-1)^s \times 0.f_{22}f_{21}\cdot\cdot\cdot f_{0} \times 2^{-126} \]
指数固定为-126,这样就可以“无缝”地与规格化浮点数相连起来。当尾数部分全部为0地时候,这个浮点数就表示0.
在标准中,+0和-0是两个数,它们只在一些微小的地方略有不同,一般不用在意。
B.1.3 特殊值
指数位全部是1的浮点数表示特殊值,包括NAN (not a number)和正负无穷大。当尾数全部为0时,根据符号位,表示正无穷或负无穷。尾数不全为0的则表示NAN。当运算结果溢出的时候会得到正负无穷的结果,一些“无意义”的计算会导致NAN。
B.2 双精度浮点数和半精度浮点数
表示方法和单精度浮点数一致,只不过指数部分有11位(表示-1022到+1023),尾数部分有52位。
半精度浮点数也是一样的,指数部分5位(表示-14到+15),尾数部分只有10位。