大多数二进制浮点数都以规格化格式 (normalized form) 存放,以便将有效数字的精度最大化。给定任意二进制浮点数,都可以进行规格化,方法是将二进制小数点移位,直到小数点左边只有一个“1”。
阶码表示的是二进制小数点向左(正阶码)或向右(负阶码)移动的位数。示例如下:
非规格化 | 规格化 |
---|---|
1110.1 | 1.1101 X 23 |
.000101 | 1.01 X 2-4 |
1010001. | 1.010001 x 26 |
规格化操作的逆操作是将二进制浮点数反规格化 (denormalize) ( 或非规格化 (unnormalize))。移动二进制小数点,直到阶码为 0。如果阶码为正数 n,则将二进制小数点右移 n 位;如果阶码为负数 n,则将二进制小数点左移 n 位,并在需要位置填充刖导数 0。
一旦符号位、阶码和有效数字字段完成规格化和编码后,生成一个完整的二进制 IEEE 段实数就很容易了。首先将设置符号位,然后是阶码字段,最后是有效数字的小数部分。例如,下面表示的是二进制 1.101 x 20:
偏移码 (01111111) 是十进制数 127 的二进制形式。所有规格化有效数字在二进制小数点的左边都有个 1,因此,不需要对这一位进行显式编码。更多的例子参见下表。
二进制数值 | 偏移阶码 | 符号、阶码、小数部分 |
---|---|---|
-1.11 | 127 | 1 01111111 11000000000000000000000 |
+1101.101 | 130 | 0 10000010 10110100000000000000000 |
-.00101 | 124 | 1 0111110001000000000000000000000 |
+100111.0 | 132 | 0 10000100 00111000000000000000000 |
+.0000001101011 | 120 | 001111000 10101100000000000000000 |
IEEE 规范包含了多种实数和非数字编码。
不定数被浮点单元 (FPU) 用于响应一些无效的浮点操作。
规格化有限数 (nonnalized finite numbers) 是指所有非零有限值,这些数能被编码为零到无穷之间的规格化实数。尽管看上去全部有限非零浮点数都应被规格化,但是若数值接近于零,则无法规格化。
当阶码范围造成的限制使得 FPU 不能将二进制小数点移动到规格化位置时,就会发生这种情况。假设 FPU 计算结果为 1.0101111 x 2-129。
其阶码太小,无法用单精度数形式存放。此时产生一个下溢异常,数值则每次将二进制小数点左移一位逐步进行非规格化,直到阶码达到有效范围:
在这个例子中,移动二进制小数点导致有效数字损失了精度。
正无穷 (+∞) 表示最大正实数,负无穷 (-∞) 表示最大负实数。无穷可以与其他数值比较:-∞ 小于 +∞,-∞ 小于任意有限数,+∞ 大于任意有限数。任一无穷都可以表示浮点溢出条件。运算结果不能规格化的原因是,结果的阶码太大而无法用有效阶码位数来表示。
NaN 是不表示任何有效实数的位模式。x86 有两种 NaN:quiet NaN 能够通过大多数算术运算来传递,而不会引起异常。signaling NaN 则被用于产生一个浮点无效操作异常。
编译器可以用 signaling NaN 填充未初始化数组,那么,任何试图在这个数组上执行的运算都会引发异常。quiet NaN 可以用于存在调试期间生成的诊断信息。程序可根据需要自由地在 NaN 中编入任何信息。FPU 不会尝试在 NaN 上执行操作。Intel 手册有一组规则确定了以这两种 NaN 为操作数的指令结果。
在浮点运算中,常常会出现一些特定的数值编码,如下表所示。字母 x 表示的位,其值可以为 1,也可以为 0。 QNaN 是 quiet NaN, SNaN 是 signaling NaN。
数值 | 符号、阶码、有效数字 |
---|---|
Positive zero | 0 00000000 00000000000000000000000 |
Negative zero | 1 00000000 00000000000000000000000 |
Positive infinity | 0 11111111 00000000000000000000000 |
Negative infinity | 1 11111111 00000000000000000000000 |
QNaN | x 11111111 1xxxxxxxxxxxxxxxxxxxxxx |
SNaN | x 11111111 0xxxxxxxxxxxxxxxxxxxxxx |