提问者:小点点

关于IEEE754浮点运算的一个问题


我想问一个关于IEEE754浮点的操作问题:

(以IEEE754单精度浮点数为例:1个符号位,8个指数位,23个尾数位)

在计算两个浮点数的加减时,指数小的尾数应与指数大的尾数对齐。

也就是说,它取决于两个浮点数之间的指数差,以查看尾数移动了多少

我的问题来了:如果指数较小的尾数超出了移位后尾数可以表达的范围。

超出范围的位我们应该一起统计,还是必须丢弃?

例如:我想计算两个浮点数的减法

第一个操作数:“0”(符号)10010011(指数)0000 0000 0000 0000 1111 111(尾数)

第二个操作数:“1”(符号)“10001110”(指数)“0000 0000 0000 0111 1111 111”(尾数)

第一个数的指数在十进制中是147,第二个数的指数在十进制中是142,并且147-127(偏差)=20,142-127=15

所以实际上上面两个数字可以变成:

第一个操作数:1.0000 0000 0000 0000 1111 111*2^20

第二个操作数:-1.0000 0000 0000 0111 1111 111*2^15

因为第二个数字比第一个数字的幂小五个,所以需要向右移动5位,那么我的问题是,它会变成:

>

  • 保留所有位,因此总共需要28位来表示尾数-0.0000 1000 0000 0000 0011 111"1 1111"(这五位超过23bit)*(2^20)

    超过23bit后直接切断,所以满足23bit意味着尾数-0.0000 1000 0000 0000 0011 111*(2^20)

    添加圆形、防护和粘性三个位来考虑,所以使用25bit来表示尾数。-0.0000 1000 0000 0000 0011 111 11=

    以上选项哪一个是对的,或者没有一个是对的?


  • 共2个答案

    匿名用户

    根据IEEE754,总是考虑所有位。该操作产生的结果与您使用实数算术计算完整结果,然后使用有效的舍入规则将其舍入以适应浮点格式相同。(舍入到最接近的,与偶数低位/位数并列,很常见,但还有其他舍入选项,例如始终向上,始终向下,朝向零,以及始终将任何非零量舍入到奇数低位。)

    这并不意味着计算机总是必须计算完整的实数结果。对于加法和减法,使用圆形、保护位和粘性位就足以得到所需的答案。对于其他操作,可能需要更复杂的算法。要求只是计算机必须计算出如果你计算完整的实数结果并对其进行四舍五入,你会得到什么——它实际上不必计算完整的实数结果。

    (“有效”是浮点表示的小数部分的首选术语。“尾数”是对数小数部分的旧术语。尾数是对数的;尾数相加会乘以表示的数字。有效数是线性的;添加到有效数会增加表示的数字。)

    匿名用户

    我的(删除的)评论走向了错误的方向。

    现在,虽然每个实现都可能受到规范和错误的错误解释的影响(历史上有很多浮点实现错误,而不仅仅是英特尔一次),但我们可以或可以尝试检查一个实现。(我的电脑)

    从一个操作数1.0开始

    0x3F800000
    
    001111111000...
    0 01111111 000...
    1.0000000 no shift
    

    然后选择一个操作数,该操作数必须移动尾数才能执行加减法。

    0x3BFFFFFF
    
    00111011111111
    0 01110111 11111
    

    这将向右移动8,所以看一些第二个操作数

    0x3BFFFFFF
    
      1.000000000000000...00 0000...
    + 0.000000011111111...11 1111...
    ==============================
      1.000000011111111...11
    
      1.000000000000000...00 0000...
    - 0.000000011111111...11 1111...
    ==============================
      1.111111100000000...00
    
    0x3BFFFF00  
    
      1.000000000000000...00 0000...
    + 0.000000011111111...11 0000...
    ==============================
      1.000000011111111...11
    
      1.000000000000000...00 0000...
    - 0.000000011111111...11 0000...
    ==============================
      1.111111100000000...10
    
    0x3BFFFF80  
    
      1.000000000000000...00 0000...
    + 0.000000011111111...11 1000...
    ==============================
      1.000000011111111...11
    
      1.000000000000000...00 0000...
    - 0.000000011111111...11 1000...
    ==============================
      1.111111100000000...01
    
    0x3BFFFFC0  
    
      1.000000000000000...00 0000...
    + 0.000000011111111...11 1100...
    ==============================
      1.000000011111111...11
    
      1.000000000000000...00 0000...
    - 0.000000011111111...11 1100...
    ==============================
      1.111111100000000...00
    
    0x3BFFFF01  
    
      1.000000000000000...00 00000000
    + 0.000000011111111...11 00000001
    =================================
      1.000000011111111...11
    
      1.000000000000000...00 00000000
    - 0.000000011111111...11 00000000
    =================================
      1.111111100000000...00 00000001
    

    对于加法(不四舍五入)基数,未移动的数字需要填充(用零)。所以尾数大小的末尾两位

    0+0 = 0 carry 0
    0+1 = 1 carry 0
    

    您不能在尾数(粘性位)之后的第一位进行进位。因此,为了添加,没有理由在第一位之后添加额外的逻辑,但您需要第一位进行四舍五入。四舍五入只需要一位。

    减法虽然你可以把它看作是借用或者…

    0x3BFFFF80
    
      1.000000000000000...00 0000...
    - 0.000000011111111...11 1000...
    ==============================
      1.111111100000000...01
    

    是真正的逻辑

                                    1
      1.000000000000000...00 00000000
    + 1.111111100000000...00 01111111
    ====================================
     10.111111100000000...00 10000000
    hardware gives
      1.111111100000000...01
    

    我仍然在纠结,因为我选择了从零开始和向下结束,所以它不应该四舍五入和/或那一点是如何到达那里的。

    无论如何,我走错了路,通过减法,这些位确实很重要,因为进位现在可以是非零的,进入尾数边缘之后的第一位,第一个操作数零扩展仍然需要用零填充,但是对于减法,如果你有一堆1,那么添加1的进位,你可以将进位一直推到尾数的边缘。

    好吧,所以我要么受到四舍五入的影响,要么我的边界错误(错误地表示了我的第二个操作数)

    0x3BFFFF80  
    
      1.000000000000000...00 0000...
    - 0.000000011111111...11 1000...
    ==============================
      1.111111100000000...01
    
    0x3BFFFFC0  
    
      1.000000000000000...00 0000...
    - 0.000000011111111...11 1100...
    ==============================
      1.111111100000000...00
    
                                    1
      1.000000000000000...00 00000000
    + ?.111111100000000...00 00111111
    =================================
    
                              1111111
      1.000000000000000...00 00000000
    + ?.111111100000000...00 00111111
    =================================
      1.111111100000000...00 01000000
    hardware gives
      1.111111100000000...00
    

    无论哪种方式bug演示中,或者不是因为在尾数末尾减法期间借用,这都会影响舍入位以及结果的lsbit(在归一化之前的尾数范围内)。

    所以答案是肯定的,这些位必须被考虑。基本上看到并投票支持埃里克的答案。

    您应该能够在其他没有严重损坏的实现上演示这一点,包括软件优化器,也许如果您可以直接从高级语言转换为二进制的特定浮点值。

    但是当在加法方面考虑它时,你不能在那里得到任何执行,所以你不能在归一化之前直接改变分数中的位,但是当然,较小数字中的分数直接影响/定义四舍五入。减法是这里的关键,因为它可以影响四舍五入和预归一化分数的进位。

    正如答案所评论的那样,是的,在逻辑上可以有捷径来不必有那么大的加法器,并且基于这个答案,显著或分数而不是尾数,抱歉…