• IEEE标准

    电气和电子工程师协会(IEEE)定义的单精度和双精度存储浮点数的标准如下图所示

    单精度占用32位,双精度占用64位。单精度和双精度符号都只占用1位(0为正,1为负)。单精度指数占用8位,使用偏移量127,位数占用23位。双精度指数占用11位,使用偏移量1023,尾数占用52位。

    • 规范化

      为了使表示法固定部分统一,科学计数法(用于十进制)和浮点数表示法(用于二进制)都在小数点左边使用了唯一非零数码,这称为规范化。十进制系统中的数码可能是1~9,而二进制系统中该数码是1。

    • 符号、指数和尾数

      在应该二进制数规范化后,我们只存储了一个数的三部分信息:符号、指数和尾数。

      1. 符号

        一个数的符号可以用一个二进制位来存储,0为正1为负。

      2. 指数

        指数(2的次幂)定义为小数点移动的位数。小数点向左移为正向右移为负。

        因为指数是有符号的数,尽管这可以用二进制补码来存储,但被一种称为余码系统的表示法取而代之。在该余码系统中,正的和负的整数可以作为无符号存储。为了表示正的或负的整数,一个偏移量加到每个数字中,将他妈统一移到非负的一边。这个偏移量的值是2^(m-1),m是内存单元存储指数的大小。

      3. 尾数

        尾数是小数点右边的二进制数。它定义了该数的精度。尾数是作为无符号整数存储的。但它不是整数,而是像整数那样存储小数部分。因为在尾数中,如果在数字左边插入多余的0,这个值会改变,而在一个真正的整数中,如果在数字左边插入多余的0,这个值不会改变。

    • IEEE标准浮点数转二进制

      1. 在S中存储符号(0或1)
      2. 将数字转换为二进制
      3. 规范化
      4. 找到E和M的值
      5. 连接S、E和M
      • 例1:将3.6875转为二进制(单精度)
        1. 符号为正:S=0

        2. 十进制转换为二进制:3.6875=0b11.1011

          1. 直接将整数部分转换为二进制(无符号):3 == 0b11

          2. 计算小数部分二进制

            1. 取小数部分乘2得到积,将积整数部分取出。接着继续用2乘以剩下的小数部分,直到积的小数部分为0,或达到精度限制。下例:
            取3.6875的小数部分:0.6875
            
            计算                  积的整数部分
            (0.6875 * 2) = 1.375     1
            (0.375  * 2) = 0.75      0
            (0.75   * 2) = 1.5       1
            (0.5    * 2) = 1.0       1 
            小数部分为0,计算结束。
            将积的整数部分按计算顺序排序即可得到小数部分的二进制:1011
            
        3. 规范化:0b11.1011 = (0b1.11011) * (2^1)

          1. 将0b11.1011的小数向左移1位,即得到0b1.11011。指数则为移动的位数(左移为正右移为负),在本例中的指数为1。规范化结果:(0b1.11011) * (2^1)
        4. 找到E和M的值

          1. E = 规范化指数 + 偏移量 = 1 + 127 = 128 = 0b10000000
          2. M = 规范化后的小数部分 = 0b11011(在后面补上23-5个0)
        5. 连接S、E、M

          1. S = 0b0,E = 0b10000000,M = 0b11011000000000000000000
          2. R = S E M = 0b0 10000000 11011000000000000000000
      • 例2:将-0.0234375转为二进制(单精度)
        1. 符号为负:S=1

        2. 十进制转二进制:0.0234375 = 0.0000011

          1. 直接将整数部分转换为二进制(无符号):0 == 0b0
          2. 计算小数部分二进制
          取0.0234375小数部分:0.0234375
          
          (0.0234375 * 2) = 0.046875   0
          (0.046875  * 2) = 0.09375    0
          (0.09375   * 2) = 0.1875     0
          (0.1875    * 2) = 0.375      0
          (0.375     * 2) = 0.75       0
          (0.75      * 2) = 1.5        1
          (0.5       * 2) = 1.0        1
          小数部分为0,计算结束。
          将积的整数部分按计算顺序排序即可得到小数部分的二进制:0000011
          
        3. 规范化:0b0.0000011 = (0b1.1) * (2^-6)

          1. 将0b0.0000011的小数向右移6位,即得到0b1.1。指数则为移动的位数(左移为正右移为负),在本例中的指数为-6。规范化结果:(0b1.1) * (2^-6)
        4. 找到E和M的值

          1. E = 规范化指数 + 偏移量 = -6 + 127 = 121 = 0b1111001
          2. M = 规范化后的小数部分 = 0b1(在后面补上23-1个0)
        5. 连接S、E、M

          1. S = 0b1,E = 0b1111001,M = 0b10000000000000000000000
          2. R = S E M = 0b1 1111001 10000000000000000000000
    • IEEE标准浮点数的数字还原

      1. 找到S、E和M的值
      2. 如果S=0,将符号设为正号,否者设为负号
      3. 找到位移量(E-偏移量)
      4. 对尾数去规范化
      5. 将去规范化对数字变为二进制以求出绝对值
      6. 加上符号

      例:位模式(0b01000000011011000000000000000000)

      1. 首位表示S,后8位表示E,剩下23位是M
        1. S = 0b0
        2. E = 0b10000000
        3. M = 0b11011000000000000000000
      2. 符号设为正号
      3. 位移量= E-127 = 0b10000000-127 = 128-127 = 1
      4. 将0b1.11011去规范化:0b1.11011 * (2^位移量) = 0b1.11011 * (2^1)
      5. 二进制数是:0b11.1011
      6. 绝对值是:3.6875
        1. 计算整数部分:0b11 = 3

        2. 计算小数部分:0.6875

          0b11.1011小数部分:1011
          
          1            0            1            1
          (1 * 2^-1) + (0 * 2^-2) + (1 * 2^-3) + (1 * 2^-4)
          = 1*0.5    + 0*0.25     + 1*0.125    + 1*0.0625
          = 0.6875
          
        3. 整数部分+小数部分:3.6875

      7. 加上符号:3.6875
    • 存储零

      带有整数部分和小数部分对实数设置为0的时候数0.0,无法用以上讨论的步骤存储。为了这个特例,约定在这种情况下符号、指数和尾数都设为0

参考资料:《计算机科学导论》