IEEE754浮点数

二进制小数

考虑十进制下的小数表示:[dmdm1d1d0d1d2dn][d_m d_{m−1}…d_1 d_0\cdot d_{−1} d_{−2}…d_{−n}],其中每个十进制数 did_i 取值范围是 0 90~9。这个表达式所描述的数值 dd 的定义为:d=Σi=nm10i×did= \Sigma^m_{i = -n}10^i\times d_i 。数字权的定义与小数点相关,在小数点的左侧,数字的权值是10的正幂,得到整数值。而小数点的右侧数字权值是10的负幂,得到小数值。如 12.341012.34_{10} 表示数字 1×101+2×100+3×101+4×102=12341001 × 10^1 + 2 × 10^0 + 3 × 10^{−1} + 4 × 10^{−2} = 12\frac{34}{100}
类似地,考虑一个形如 [bmbm1b1b0b1b2bn][b_m b_{m−1}…b_1 b_0\cdot b_{−1} b_{−2}…b_{−n}] 的表达式,其中的每个二进制数字 bib_i 的取值范围是 0011,这种表示方法表示的数定义为:b=Σi=nm2i×bib=\Sigma_{i=−n}^m 2^i × b_i 。同样的,小数点的左侧数字权值为 22 的正幂,右侧数字权值为 22 的负幂。如 101.112101.11_2 表示数字 1×22+0×21+1×20+1×21+1×22=5341 × 2^2 + 0 × 2^1 + 1 × 2^0 + 1 × 2^{−1} + 1 × 2^{−2} = 5\frac{3}{4} 。这种表示法称为浮点数的定点表示法。
如果仅考虑有限长度的编码,那么上述十进制小数无法准确表示如 1/3,5/71/3,5/7 这样的数。类似地,小数的二进制表示法也智能表示具有 x×2yx×2^y 形式的数,其他的值只能近似表示。

IEEE浮点表示

定点表示法无法有效表示非常大的数字。例如表达式 5×21005×2^100 是用 101101 后面跟随 100100 个零的位模式来表示。
IEEE浮点标准用 V=(1)s×M×2EV=(−1)^s×M×2^E 的形式来表示一个数:

  • 符号(sign)s决定这个数是正数 (s=0)(s=0) 还是负数 (s=1)(s=1),数值为00时符号位的解释作为特殊情况处理
  • 尾数(significand)M是一个二进制小数,它的范围是 12ϵ1\thicksim 2−ϵ,或是 01ϵ01\thicksim ϵ
  • 阶码(exponent)E的作用是对浮点数加权,这个权重是 22EE (可能是负数)次幂
    将浮点数的位表示划分为三个字段,分别对这些值进行编码:
  • 一个单独的符号位 s 直接编码符号 s
  • k位的阶码字段 exp=ek1e1e0exp=e_{k−1}…e_1 e_0 编码阶码 E
  • n位小数字段 frac=fn1f1f0frac=f_{n−1}…f_1 f_0 编码尾数 M,该字段的解释依赖于阶码字段的值是否为0
    下图所示是这三个字段在字中的两种最常见格式,对于单精度浮点数,sexpfrac字段分别为 1823 位;对于双精度浮点数,sexpfrac 字段分别为 11152 位。

对于一个给定的浮点数位表示,对其的解释根据阶码字段的值可以分成三种情况(最后一种情况有两个变种):

  1. 情况1:规格化的值
    这是最普遍的情况。当 exp的位模式既不全为零(数值0),也不全为1 (单精度情况下数值为255,双精度数值为2047)时,属于这种情况。
    此时阶码字段被解释为以 偏置(biased) 形式的有符号整数,即:E=eBiasE = e - Bias,其中 ee 是阶码字段编码的无符号数,BiasBias 是一个等于 2k112^{k−1}−1(单精度是 127127,双精度是 10231023 )的偏置值 。此时产生的指数范围,对于单精度是 126+127−126\thicksim +127,对于双精度是 1022+1023−1022\thicksim +1023
    小数字段 fracfrac 被解释为小数值 ff,其中 0f<10≤f<1,其二进制表示为:$ 0.f_{n−1}…f_1 f_0$ ,即所有位的权都是2的负幂。尾数 MM 定义为 M=1+fM=1+f 。这种方式叫做隐含的以1开头的(implied leading 1)表示,可以将位数的位表示看作 1.fn1f1f01.f_{n−1}…f_1 f_0。由于总是可以通过调整阶码 EE,使得尾数 MM 保持在范围 1M<21≤M<2 中,那么这种方法可以无代价的获得一个额外的精度位。
  2. 情况2:非规格化的值
    阶码域为全0时,所表示的数是非规格化的值。此时阶码值是E=1BiasE = 1-Bias,尾数的值是M=fM = f,不包含隐含开头的11
    非规格化的表示有两个用途:
    1. 它提供了一种表示00的方法,在规格化的情况下,MM总是大于等于11的,因此无法表示00。实际上,+0.0+0.0的位模式为全00,符号位,阶码和小数域全为00;而当符号位为11,阶码和小数域为00时,该值被解释为0.0-0.0
    2. 非规格化数的第二个功能是表示非常接近0.00.0的数。它提供了一种称为逐渐下溢(gradual underflow)的特性,让数值的分布均匀地接近0.00.0

Note: 使阶码值为1-Bias而不是简单的-Bias是因为这样可以补偿尾数值由M=f+1变为M=f后造成的数值突变,使数值从非规格数到规格数能够更加平滑的变化

  1. 情况3:特殊值
    最后一类数值是当阶码全为1时出现的。
    当小数域全为 00 时,得到的值表示无穷,当 s=0s=0 时表示正无穷,或者当 s=1s=1 时是负无穷。当把两个非常大的数相乘,或者除以 00 时,无穷能够表示溢出的结果。
    当小数域非0时,结果被称为"NaN",即"不是一个数"。如 1\sqrt{-1}]]\infin−\infin的结果是NaN

Note: 假如将从0到最大值排列的一组无符号数的位模式按照相同字长的浮点数解释,则浮点数结果也是递增的。IEEE格式设计点之一就是为了浮点数能够直接使用整数的排序函数。

对于有k位阶码和n位小数域的浮点数表示,其具有以下属性:

描述 expexp fracfrac 值(单精度) 十进制(单精度) 值(双精度) 十进制(双精度)
00 000000…00 0000…00 00 0.00.0 00 0.00.0
最小非规格化正数 000000…00 0010…01 223×21262^{−23}×2^{−126} 1.4×10451.4×10^{−45} 252×210222^{−52}×2^{−1022} 4.9×103244.9×10^{−324}
最大非规格化数 000000…00 1111…11 (1ϵ)×2126(1−ϵ)×2^{−126} 1.2×10381.2×10^{−38} (1ϵ)×21022(1−ϵ)×2^{−1022} 2.2×103082.2×10^{−308}
最小规格化数 000100…01 0000…00 1×21261×2^{−126} 1.2×10381.2×10^{−38} 1×210221×2^{−1022} 2.2×103082.2×10^{−308}
11 011101…11 0000…00 1×201×2^0 1.01.0 1×201×2^0 1.01.0
最大规格化数 111011…10 1111…11 (2ϵ)×2127(2−ϵ)×2^{127} 3.4×10383.4×10^{38} (2ϵ)×21023(2−ϵ)×2^{1023} 1.8×103081.8×10^{308}
  • +0.0+0.0 总有一个全0的表示
  • 最小的正非规格化的值的位表示,是由最低有效位为1而其他所有位为00构成的。它具有小数(此时即尾数)值M=f=2nM=f=2^{−n} 和阶码值E=2k1+2E=−2^{k−1}+2。因此该表示的数值为V=2n2k1+2V=2^{−n−2^{k−1}+2}
  • 最大的非规格化值的位模式是由全为00的阶码字段和全为11的小数字段组成的。它具有小数(此时即尾数)值M=f=12nM=f=1−2^{−n} (写成1ϵ1−ϵ)和阶码值E=2k1+2E=−2^{k−1}+2,因此数值V=(12n)×22k1+2V=(1−2^{−n})×2^{−2^{k−1}+2}
  • 最小的正规格化值位模式的阶码字段最低有效位为11,其他位全为00。它的尾数值M=1M=1,而阶码值E=2k1+2E=−2^{k−1}+2。因此数值V=22k1+2V=2^{−2^{k−1}+2} 。值得注意的是,这之比最大的非规格化值大一点。
  • 1.01.0 的位表示阶码字段除了最高有效位为00之外,所有其他位都为11。它的尾数M=1M=1,它的阶码值E=0E=0
  • 最大的规格化值的位表示的符号位为00,阶码的最低有效位为00,其他位均为11。它的小数值f=12nf=1−2^{−n},尾数值M=22nM=2−2^{−n} (写作2ϵ2−ϵ)。阶码值E=2k11E=2^{k−1}−1,得到数值V=(22n)×22k11V=(2−2^{−n} )×2^{2^{k−1}−1}

舍入

对于无法准确表示的值,浮点数采用 向偶数舍入(round to even) 的规则来获得一个近似值。
向偶数舍入也称向 最近值舍入(round to nearest) ,它试图找到一个最接近的匹配值。例如,它将 1.41.4 舍入成11,而将1.61.6舍入成22,因为它们是最接近的值。对于处于两个可能值正中间的值,向偶数舍入采取的策略是使得结果的最低有效数字是偶数。因此这种方法将1.51.52.52.5都舍入成22
浮点数采用这种舍入规则的原因是,对于一组数据而言,如果都采用向上舍入或向下舍入,会不可避免的带来统计偏差,而向偶数舍入可以在大多数情况下避免这种偏差。
对于二进制小数来说,将最低有效位的值00视为偶数,值11视为奇数。对于处于两种可能值正中间的值来说,舍入后的结果要保证最低有效位为00。如10.111002(278)10.11100_2 (2 \frac{7}{8})被舍入为11.002(3)11.00_2 (3)10.101002(258)10.10100_2 (2 \frac{5}{8})被舍入为10.102(212)10.10_2 (2 \frac{1}{2})

浮点运算

IEEE规定的浮点数运算中,把浮点数xxyy看作是实数,浮点数x,yx,y运算的结果实际上是实数x,yx,y精确运算后舍入的结果。
考虑到舍入的影响,可以将浮点数加法x+fyx+^f y定义为Round(x+y)Round(x+y),即对实数结果舍入。对于所有的浮点数,该运算是可交换的,即x+fy=y+fxx+^f y=y+^f x,另一方面,该运算是不可结合的,即x+f(y+fz)(x+fy)+fzx+^f (y+^f z)\neq (x+^f y) +^f z。例如在单精度浮点数中,(3.14+1e10)1e10=0.0(3.14+1e10)−1e10=0.0,这是由于舍入,在1e101e10的大小尺度下,3.143.14被舍去了,同时3.14+(1e101e10)=3.143.14+(1e10−1e10)=3.14
对于乘法浮点数也有类似的属性:浮点数乘法是可交换的,即x×fy=y×fxx×^f y=y×^f x。但同时是不可结合的,例如在单精度条件下:(1e201e20)1e20=+(1e20∗1e20)∗1e−20=+∞,而1e20(1e201e20)=1e201e20∗(1e20∗1e−20)=1e20。另外,浮点数乘法不具分配性,例如单精度条件下:1e20(1e201e20)=0.01e20∗(1e20−1e20)=0.0,而1e201e201e201e20=NaN1e20∗1e20−1e20∗1e20=NaN
浮点数运算还具有如下的性质,对于任意a,b,cNaNa, b ,c\neq NaN:

{ab,c0a×fcb×fcab,c0a×fcb×fca×fa0\begin{cases} a \geqslant b, c \geqslant 0 \Rightarrow a \times^f c \geqslant b \times^f c \\ a \geqslant b, c \leqslant 0 \Rightarrow a \times^f c \leqslant b \times^f c \\ a \times^f a \geqslant 0 \end{cases}

Note: C语言标准中并未要求机器使用IEEE浮点数