深入理解计算机系统(CSAPP):第二章.信息的表示和处理

2.4 浮点数

        浮点表示对形如 V = x * 2^{y}的有理数进行编码。他对执行涉及非常大的数字\left | V \right | \gg 0、非常接近于0的数字 \left | V \right | \ll 1,以及更普遍的作为实数运算的近似值的计算,是很有用的。

        直到20世纪80年代,每个计算机制造商都设计了自己的表示浮点数的规则,以及对浮点数执行运算的细节。另外,他们常常不会太多的关注运算的精确性,而把实现的速度和简便性看的比数字的精确性更重要。

        大约在1985年,这些情况随着IEEE标准754的推出而改变了,这是一个仔细制定的表示浮点数及其运算的标准。这项工作从1976年开始有Intel赞助的,与8087的设计同时进行,8087是一种为8086处理器提供浮点支持的芯片,他们请William Kahan作为顾问,帮助设计未来处理器浮点标准。目前,实际上所有的计算机都支持这个后来被称为IEEE浮点的标准。着大大的提高了科学应用程序在不同机器上的可移植性。

        在本节中,我们将看到IEEE浮点格式中数字是如何表示的。我们还将探讨舍入的问题。即当一个数字不能被准确的表示为这种格式时,就必须向上调整或者向下调整。然后我们将探讨加法、乘法和关系运算符的数学属性。

2.4.1 二进制小数

        理解浮点数的第一步是考虑含有小数值的二进制数字。首先,让我们来看看更熟悉的十进制表示法。十进制表示法使用如下形式的表示:

   d_{m}d_{m-1}....d_{1}d_{0}.d_{-1}d_{-2}...d_{-n}

其中每个十进制数的取值范围是0~9。这个表达描述的数值d定义如下:

        d =\sum_{i=-n}^{m} 10^{i} * d_{i}

        数字权的定义与十进制小数点符号相关,这意味着小数点左边的数字的权是10的正幂,得到整数值,而小数点右边的数字的权是10的负幂,得到小数值。

        假定我们仅考虑有限长度的编码,那么十进制表示法不能准确的表达像 1/3和 5/7这样的数,类似,小数的二进制表示法只能表示那些能够被写成 x*2^{y} 的数。其他的值只能近似的表示。例如,数字1/5可以用十进制小数0.20精确表示。不过我们并不能把它们准确的表示为一个二进制小数,我们只能近似的表示他,增加二进制表示的长度可以提高表示的精度。

2.4.2 IEEE浮点表示

        前一节中谈到的定点表示法不能很有效的表示非常大的数字。例如,表达式5*2^{100}是用100后面跟随100个零的位模式来表示的。相反,我们希望通过给定x和y的值,来表示 x *2^{y}的数。

        IEEE浮点标准用v=\left ( -1 \right )^{s} *M * 2^{E}的形式来表示一个数:

  • 符号(sign) s决定这个数是负数(s=1) 还是正数(s=0),而对于数值0的符号位解释作为特殊情况处理。
  • 尾数(significand) M是一个二进制小数。
  • 阶码(exponent) E的作用是对浮点数加权,这个权重是2的E次幂。

        将浮点数的位表示划分为三个字段,分别对这些值进行编码:

  • 一个单独的符号位s 直接编码符号s。
  • k位的阶码字段 exp= e_{k-1}...e_{1}e_{0} 编码阶码E。
  • n位小数字段 frac = f_{n-1}...f_{1}f_{0}编码尾数M,但是编码出来的值也依赖于阶码字段的值是否等于0

        图2-32中给出了将这3个字段装进字中最常见的格式。在单精度浮点格式中,s、exp和frac 字段分别为1位,k=8位和n=23位,得到一个32位的表示。在双精度中,s、exp和frac 字段分别为1位、k=11位和n=52位,得到一个64位表示

2-32 标准浮点格式

        给定位表示,根据exp的值,被编码的值可以分成三种不同的情况。图2-33 说明了对单精度格式的情况 

2-33 单精度浮点数值的分类

 情况1:规格化的值:

        这种情况是最普遍的。当exp 的位模式既不全为0,也不全为1时,都属于这类情况。在这种情况中,阶码字段被解释为偏置形式表示的有符号整数。也就是说,阶码的值是 E = e-Bias,其中e是无符号数,其位表示为 e_{k-1}...e_{1}e_{0}而Bias是一个等于2^{k-1} -1的偏置值。由此产生指数的取值范围。

        小数字段frac被解释为描述小数值f,其中0\leq f < 1,其二进制表示为0.f_{n-1}....f_{1}f_{0},也就是二进制小数在最高有效位的左边。尾数定义为 M = 1+f。有时,这种方式也叫做隐含的以1开头的表示,因为我们可以吧M看成一个二进制表达式为 1.f_{n-1}f_{n-2}....f_{0}。既然我们总是能够调整阶码E,使得尾数M在范围 1\leq M < 2之中,那么这种表示方法是一种轻松获得一个额外精度位的技巧。既然第一位总是等于1,那么我们就不需要显式的表示他。

 情况2:非规格化的值

        当阶码域全0时,所表示的数是非规格化形式。在这种情况下,阶码值是E = 1-Bias,而尾数M=f,也就是小数字段的值,不包含隐含的开头的1。

        非规格化数有两个用途。首先,他们提供了一种表示数值0的方法,因为使用规格数,我们必须总是是M≥1,因此我们不能表示0。实际上,+0.0的浮点表示位模式为全0,符号位是0,阶码字段全为0,而小数域也全是0,这就得到了M=f=0。令人奇怪的是,当符号位为1,而其他域全为0时,我们得到值-0.0.根据IEEE浮点格式,值+0.0和-0.0在某些方面被认为是不同的,而在其他方面是相同的。

        非规格化数的另外一个功能就是表示哪些非常接近于0.0的数。他们提供了一种属性,称为逐渐下溢,其中,可能的数值分布均匀的接近于0.0。

情况3:特殊值

        最后一类数值是当值阶码全为1时的时候出现的。当小数域全为0时,得到的值表示无穷,当s=0时是+∞,或者当s=1时是-∞。当我们把两个非常大的数相乘,或者除以零时,无穷能够表示溢出的结果。当小数域为非零时,结果值被称为“NaN”,即“不是一个数”的缩写。一些运算的结果不能是实数或无穷,就会返回这样的“NaN”值,比如当计算\sqrt{-1} 或 ∞ - ∞ 时,在某些应用中,表示未初始化的数据时,他们也很有用处。

2.4.3 数字示例

        图 2-34 展示了一组数值,他们可以用假定的6位格式来表示,有k=3的阶码位和n=2的位数。偏置量是 2^{3-1} -1 =3 。图中的a部分显示了所有可表示的值。两个无穷值在两个末端。最大数值的规格化数是±14。非规格化数聚集在0的附近。图b部分中,我们只展示了介于-1.0和+1.0之间的数值,这样就能够看得更加清楚了。两个零是特殊的非规格化数。可以观察到,那些可表示的数并不是均匀分布的——越靠近原点处他们越稠密。

        图2-35 展示了假定的8位浮点格式的示例,其中k=4的阶码位和n=3的小数位。偏置量为2^{4-1} -1 = 7。图被分成三个区域,来描述三类数字。不同的列给出了阶码字段是如何编码阶码E的,小数字段是如何编码为数M的,以及他们一起是如何形成要表示的值V = 2^{E} * M的。从0自身开始,最靠近0的是非规格化数。这种格式的非规格化数的E=1-7 = -6,得到权 2^{E} = \frac{1}{64}。小数f的值的范围是 0,\frac{1}{8},...,\frac{7}{8},从而得到范围 0 \sim \frac{1}{64}*\frac{7}{8} = \frac{7}{512}

图2-35 8位浮点格式的非负值示例
描述位表示指数小数

eE2^{E}fM2^{E}*MV十进制
00 0000 0000-6\frac{1}{64}\frac{0}{8}\frac{0}{8}\frac{0}{512}00.0
最小的非规格化数0 0000 0010-6\frac{1}{64}\frac{1}{8}\frac{1}{8}\frac{1}{512}\frac{1}{512}0.001953
0 0000 0100-6\frac{1}{64}\frac{2}{8}\frac{2}{8}\frac{2}{512}\frac{1}{256}0.003906
0 0000 0110-6\frac{1}{64}\frac{3}{8}\frac{3}{8}\frac{3}{512}\frac{3}{512}0.005859
......
最大的非规格化数0 0000 1110-6\frac{1}{64}\frac{7}{8}\frac{7}{8}\frac{7}{512}\frac{7}{512}0.013672
最小的规格化数0 0001 0001-6\frac{1}{64}\frac{0}{8}\frac{8}{8}\frac{8}{512}\frac{1}{64}0.015625
0 0001 0011-6\frac{1}{64}\frac{1}{8}\frac{9}{8}\frac{9}{512}\frac{9}{512}0.017578
......
10 0110 1106-1\frac{1}{2}\frac{6}{8}\frac{14}{8}\frac{14}{16}\frac{7}{8}0.875
0 0110 1116-1\frac{1}{2}\frac{7}{8}\frac{15}{8}\frac{15}{16}\frac{15}{16}0.9375
0 0111 000701\frac{0}{8}\frac{8}{8}\frac{8}{8}11.0
0 0111 001701\frac{1}{8}\frac{9}{8}\frac{9}{8}\frac{9}{8}1.125
0 0111 010701\frac{2}{8}\frac{10}{8}\frac{10}{8}\frac{5}{4}1.25
......
0 1110 110147128\frac{6}{8}\frac{14}{8}\frac{1792}{8}224224.0
最大的规格化数0 1110 111147128\frac{7}{8}\frac{15}{8}\frac{1920}{8}240240.0
无穷大0 1111 000-------

        图2-36展示了一些重要的单精度和双精度浮点数表示和数字值。根据图2-35中展示的8位格式,我们能够看出有k位阶码和n位小数的浮点数表示的一般属性。

        

图2-36 非负浮点数的示例
描述expfrac单精度双精度
十进制十进制
000......000......0000.000.0
最小非规格化数00......000......012^{-23}*2^{-126}1.4*10^{-45}2^{-52}*2^{-1022}4.9*10^{-324}
最大非规格化数00......001......11\left ( 1-\varepsilon \right )*2^{-126}1.2*10^{-38}\left ( 1-\varepsilon \right )*2^{-1022}2.2*10^{-308}
最小规格化数00......010......001*2^{-126}1.2*10^{-38}1*2^{-1022}2.2*10^{-308}
101......110......001*2^{0}1.01*2^{0}1.0
最大规格化数11......101......11\left ( 2-\varepsilon \right ) *2^{127}3.4*10^{38}\left ( 2-\varepsilon \right ) *2^{1023}1.8 *10^{308}
  • 值+0.0总有一个全为0的位表示。
  • 最小的正规格化值的表示,是由最低有效位为1而其他所有位为0构成的。它具有小数(和尾数)值 M = f = 2^{-n} 和阶码值 E = -2^{k-1}+2。因此它的数字值是 V = 2^{-n-2^{k-1}+2}
  • 最大的非规格化值的位模式是由全为0的阶码字段和全为1的小数字段组成的。他有小数(和尾数)值M = f = 1-2^{-n}(我们写成1-\varepsilon)和阶码值 E = -2^{k-1}+2。因此数值 V = \left (1-2^{-n} \right ) *2^{-2^{k-1}+2},这仅比最小的规格化值小一点。
  • 最小的正规格化值的位模式的阶码字段的最低有效位为1,其他位全为0。他的尾数值M=1,而阶码值 E = - 2^{k-1}+2。因此,数值V=2^{-2^{k-1}+2}
  • 值1.0的位表示的阶码字段除了最高有效位等于0外,所有其他位都等于1。他的尾数值是 M=1,而他的阶码值是E=0。
  • 最大的规格化值的位表示的符号位时0,阶码的最低有效位等于0,其他位等于1。他的小数值f=1-2^{-n} ,尾数M=2-2^{-n}。他的阶码值E=2^{k-1}-1,得到数值  V=\left ( 2-2^{n} \right )*2^{2^{k-1}-1}  =\left ( 1-2^{-n-1} \right ) * 2^{2^{k-1}}

2.4.4 舍入

        因为表示方法限制了浮点数的范围和精度,所以浮点运算只能近似的表示实数运算。因此,对于值x,我们一般想用一种系统的方法,能够找到“最接近”比配置x,他可以用期望的浮点形式表示出来。这就是舍入运算的任务。一个关键问题是在于两个可能值的中间确定舍入方向。例如,如果我有1.50美元,想把它舍入到最接近的美元数,应该是1美元还是2美元呢?一种可选择的方法是未出实际的数字的上界和下界。例如,我们可以确定可表示的值x^{-}x^{+},使得x的值位于他们之间。IEEE浮点格式定义了四种不同的舍入方式。默认的方法是找到最接近的匹配,而其他三种可用于计算上界和下界。

        图2-37举例说明了四种舍入方式,讲一个金额数舍入到最接近的整数美元数。向偶数舍入,也被称为向最近的值舍入,是默认的方式,试图找到一个最接近的匹配值。因此,它将1.40美元舍入成1美元,而将1.6美元舍入成2美元,因为他们是最接近的整数美元值。唯一的设计决策是确定两个可能结果中间数值的舍入效果。向偶数舍入方式采用的方法是:它将数字向上或者向下舍入,是的结果的最低有效数字是偶数。因此,这种方法将1.5美元和2.5美元都舍入成2美元。

图2-37 以美元舍入为例说明舍入方式
方式1.401.601.502.50-1.50
向偶数舍入1222-2
向零舍入1112-1
向下舍入1112-2
向上舍入2223-1

        其他三种凡是产生的实际值的确界。这些方法在一些数字应用中是很有用的。向零舍入方式是把正数向下舍入,把负数向上舍入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值