deep-learn-ieee754

抛出问题

  1. 为什么会有偏移量, 即为什么要设置阶码
  2. 整数到浮点数的转换是怎么实现的
  3. 舍入的方式

IEEE浮点表示

IEEE浮点标准用V = (-1)^s x M x 2^ E的形式来表示一个数:

  • 符号(sign) s决定着数是负数(s=1)还是正数(s=0), 而对于数值0的符号位解释作为特殊情况处理.
  • 尾数(significand) M是一个二进制小数, 它的范围是12-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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. 规格化的
-------------------------------------------
| s | !=0&!=255 | f |
-------------------------------------------
2. 非规格化的
-------------------------------------------
| s |0|0|0|0|0|0|0| f |
-------------------------------------------
3a. 无穷大
------------------------------------------------------------------
| s |0|0|0|0|0|0|0| 0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|
------------------------------------------------------------------
3b. NaN
-------------------------------------------
| s |1|1|1|1|1|1|1| !=0 |
-------------------------------------------

情况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的方向舍入。