抛出问题
- 为什么会有偏移量, 即为什么要设置阶码
- 整数到浮点数的转换是怎么实现的
- 舍入的方式
IEEE浮点表示
IEEE浮点标准用V = (-1)^s x M x 2^ E的形式来表示一个数:
- 符号(sign) s决定着数是负数(s=1)还是正数(s=0), 而对于数值0的符号位解释作为特殊情况处理.
- 尾数(significand) M是一个二进制小数, 它的范围是1
2-x, 或者是01-x. - 阶码(exponent) E的作用是对浮点数加权. 这个权重是2的E次幂(可能是负数). 将浮点数的位表示划分为三个字段, 分别对这些值进行编码:
- 一个单独的符号位s直接编码符号s
- k位的阶码字段exp编码阶码E
- n位小数字段frac编码尾数M, 但是编码出来的值也依赖于阶码字段的值是否等于0
在单精度浮点格式(C语言中的float)中, s, exp和frac字段分别为1位, k=8位和n=32位, 得到一个32位的表示
在双精度浮点格式(C语言中的double)中, s, exp和frac字段分别位1位, k=11位和n=52位, 得到一个64位的表示.
三种不同的情况
1 | 1. 规格化的 |
情况1: 规格化的值
这是最普遍的情况. 当exp的位模式既不全为0(数值0), 也不全为1(单精度数值位255, 双精度数值位2047)时, 都属于这类情况. 在这种情况中, 阶码字段被解释位以偏置(biased)形式表示的有符号整数. 也就是说, 阶码的值是E=e-Bias, 其中e是无符号数, Bias是一个等于2^{k-1}-1(单精度是127, 双精度是1023)的偏置值. 由此产生指数的取值范围, 对于单精度是-126+127, 而对于双精度是-1022+1023.
采用这种方式表示的目的是简化比较. 因为, 指数的值可能为正也可能为负, 如果采用补码表示的化, 全体符号位S和Exp自身的符号位将导致不能简单的进行大小比较. 正因为如此, 指数部分通常采用一个无符号的正数值存储.
小数字段frac被解释为描述小数值f, 其二进制表达式为1.f_{k-1}….f2f1f,其中0 =< f < 1, 尾数定义为M=1+f. 有时, 这种方式也叫做隐含的以1开头的(implied leading 1)表示, 因为我们可以把M看成一个二进制表达式为1.f_{k-1}….f2f1f的数字. 既然我们总是能够调整阶码E, 使得尾数M在范围 1=< 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的数. 它们提供了一种属性, 称为逐渐下溢(gradual underflow), 其中. 可能的数值分布均匀地接近于0.0
特殊值
最后一类数值是当指阶码全为1的时候出现的. 当小数域全为0时, 得到的值表示无穷, 当s=0时是正无穷, 或者当s=1时是负无穷. 当我们把两个非常大的数相乘, 或者除以零时, 无穷能够表示溢出的结果. 当小数域为非零时, 结果值被称为”NaN”, 即”不是一个数(Not a Number)”的缩写. 一些运算的结果不能是实数或无穷, 就会返回这样的NaN值.
浮点数的比较
浮点数基本上可以按照符号位, 指数域, 尾数域的顺序做字典比较. 显然, 所有正数大于负数; 正负号相同时, 指数的二进制表示法更大的其浮点数值更大.
浮点数的舍入
任何有效数上的运算结果, 通常都存放在较长的寄存器中, 当结果别放回浮点格式时, 必须将多次出来的比特丢弃. 有多种方法执行舍入作业, 实际上IEEE标准列出4中不同的方法:
- 舍入到最接近: 舍入到最接近, 在一样接近的情况下偶数优先(Ties To Even, 这是默认的舍入方式): 会将结果舍入为最接近且可以表示的值, 但是当存在两个数一样接近的时候, 则取其中的偶数(在二进制中是以0结尾的).
- 朝+∞方向舍入:会将结果朝正无限大的方向舍入。
- 朝-∞方向舍入:会将结果朝负无限大的方向舍入。
- 朝0方向舍入:会将结果朝0的方向舍入。