Floating Point

402 阅读4分钟

加深理解代替单纯记忆

本文转述了《深入理解计算机系统》一书中Float Pointing章节的内容,以期对浮点数的内部结构有深入的理解

Floating Point

IEEE规定了浮点数的二进制的存储表达规范,可以用于表示形如V = (-1) ^ s * M * 2 ^ E的浮点数

其中

  • s(sign)表示正负,0为正,1位负
  • M表示有效位数(significand),或者成为小数部分(fraction)
    • M可以表示1.xxx0.xxx样式的值
  • E表示指数部分

对应单浮点数(float)双浮点数(double),其在内存中的存储样子是这样

注意第三行表示的是双浮点数0-32位部分

  • 两类浮点数符号位都只占1位
  • 单浮点数,8位用于表示指数部分,23位用于表示小数部分
  • 双浮点数,11位用于表示指数,52位用于表示小数

二进制数转换到最终小数

最终的小数值,并不是将上面内存中二进制的数转为十进制,再套上前面V = xxx公式的结果。中间可能需要做一些转换,还有一些特殊情况要考虑

根据exponent部分不同的取值,浮点数可以分为三种case

Normalized ValuesDenormalized ValuesSpecial Values

最终的小数值,是根据这三种不同情况,得出最终的s、M、E,再套用公式计算后的结果

Normalized Values

要求exponent部分既不全都是0,也不全都是1。该类型的值最普遍

  • 该情况下E = e - Bias
    • e是exponent区域二进制数的无符号十进制值
    • Bias是一个偏移量值,单浮点数时是127,双浮点时是1023(Bias的值是2^k - 1计算得来,k表示e部分所占的位数)
    • 单浮点时E的取值是-126-127,双浮点数是-1022-1023
  • M的值可以表示为M = 1 + f
    • f就是fraction部分表示的二进制小数
    • 之所以要加1,其实是为了实现让1 <= M < 2,同时又不想占用fraction部分的位置,取巧的做法
    • 上面取巧的做法叫做implied leading 1

Denormalized Values

要求exponent部分全是0

  • E部分值E = 1 - Bias
  • M的值和f部分的二进制值含义一致
  • Denormalized Values有两个作用
    • 用于表示0,因为Normalized Values下,M的值始终是1.xxx,无法表示0.
    • 表示0时--sign部分决定正负,其余部分全是0。IEEE规定+0和-0在有些情况下含义不同
    • 另一个作用是更适合表示很接近0的值

Special Values

exponent区域都是1时,表示一些特殊值(Special Value)

  • fraction部分全是0时,则表示无穷大(Infinity)
    • sign部分是0时,表示正无穷大
    • sign是1时,表示负无穷大
    • 通常,无穷大表示越界(overflow),比如两个大数相乘、0作为除数
  • fraction不全是0时,表示NAN,即not a number
    • 该值用于表示,通过正常的计算规则无法得出正常结果的情况。比如对-1开根号,正负无穷加正无穷

Rounding

由于IEEE对二进制浮点数表示的规范限制,我们知道计算机实际上能表示的浮点数是可以枚举的,当我们所需的精确的浮点数无法在计算机中表示时,或者我们要对浮点数部分有效位时,此时就需要rounding--截断

下面先通过十进制的数字(以十进制金额距离)来解释一下四种rounding模式,后面会再对二进制的浮点数进行说明

Mode $1.40 $1.60 $1.50 $2.50 $-1.50
Round to even 1 2 2 2 -2
Round toward zero 1 1 1 2 -1
Round down 1 1 1 2 -2
Round up 2 2 2 3 -1
  • Round to even
    1. 向最接近的值截断
    2. 若当前值正好处中前后两值中间位置,则向偶数截断
  • Round toward zero 向靠近0的方向截断
  • Round down 向值小的方向截断
  • Round up 向值大的方向截断

理解了几个模式后我们再看一下二进制下浮点数的rounding行为

默认的rounding模式是 Round to even

在浮点数中,使用Round to even时,当值正好处在前后值的中间位置时,截断时认为0是even,1是odd,具体看下面例子

假设使用Round to even模式,对下面的值保留小数点后两位,截断结果如表所示

Round to even
10.00011 10.00
10.00110 10.01
10.11100 11.00
10.10100 10.10

分析过程

既然保留小数点后两位,我们只需要看从第三位开始的值即可

  • 10.00011,10.00的下一个值是10.01,从10.00到10.01,中间值是10.001,那么10.00011比10.001小,所以结果应该是10.00
  • 10.00110可根据上面一条同理分析
  • 10.1110,10.11的下一个值是11.00,从10.11到11.00,中间值是10.111,那正好处在了中间值位置,我们选择偶数,也就是最终结果中最后一位是0的,即11.00
  • 10.10100,10.10到下一个值10.11,中间值是10.101,选择偶数,即为10.10