【问题标题】:A problem about IEEE 754 floating point operation一个关于 IEEE 754 浮点运算的问题
【发布时间】:2020-09-18 14:29:52
【问题描述】:

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

(以IEEE 754单精度浮点数为例: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,需要右移5位,那么我的问题是,会变成:

  1. 所有位都是保留的,所以一共需要28位来表示尾数 -0.0000 1000 0000 0000 0011 111 "1 1111"(这五个位超过23bit) * (2 ^ 20)

  2. 超过23bit后直接截断,所以满足23bit就是尾数 -0.0000 1000 0000 0000 0011 111 * (2 ^ 20)

  3. 加上round、guard、sticky这三位考虑,所以用25bit来表示尾数。 -0.0000 1000 0000 0000 0011 111 11 =>最后两位(第24位和第25位)为保护位和轮位,并设置S = 1(因为最后三个1被截断)

以上选项哪一个是对的还是一个都不对?

【问题讨论】:

  • @old_timer 对不起,我不太明白你的意思,你能把你的评论说清楚吗?谢谢
  • 虽然具体的实现是对规范的解释,你仍然可以用具体的实现来尝试,应该有点简单。看看结果是什么(需要减去而不是添加)。

标签: floating-point precision ieee-754


【解决方案1】:

根据 IEEE 754,始终考虑所有位。该操作产生的结果与您使用实数算术计算完整结果然后使用任何有效的舍入规则将其舍入以适合浮点格式的结果相同。 (四舍五入,与偶数低位/数字相关,很常见,但还有其他舍入选项,例如始终向上、始终向下、趋近零,以及始终将任何非零值舍入到奇数低位。)

这并不意味着计算机总是必须计算完整的实数结果。对于加法和减法,使用 round、guard 和 sticky 位就足以得到所需的答案。对于其他操作,可能需要更复杂的算法。要求仅仅是计算机必须弄清楚如果您计算出完整的实数结果并将其四舍五入会得到什么——它实际上不必计算出完整的实数结果。

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

【讨论】:

  • 谢谢你的回答。所以根据你所说的“根据 IEEE 754,总是考虑所有位。这是否意味着如果我想移动浮点数 -1.0000 0000 0000 0111 1111 111 * (2 ^ 15) 右移5位,则结果为-0.0000 1000 0000 0000 0011 1111 1111 * 2^20(小数共有28位,保留所有位),然后与第一个相减即,1.0000 0000 0000 0000 1111 111 -0.0000 1000 0000 0000 0011 1111 1111。我说的对吗?
【解决方案2】:

我的(已删除)评论的方向是错误的。

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

从一个操作数 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

我仍在纠结,因为我选择了舍入为零和向下舍入,所以它不应该向上舍入和/或那个位是如何到达那里的。

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

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

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

由于减法期间的借用,演示中是否存在错误 结束尾数,这会影响舍入位和结果的 lsbit(在归一化之前的尾数范围内)。

所以答案是肯定的,必须考虑这些位。基本上看到并投票给 Eric 的答案。

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

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

并且作为答案 cmets,是的,在逻辑上可以有捷径,不必有那么大的加法器,并且还基于该答案,显着或分数而不是尾数,对不起......从那以后一直使用旧术语回到不是旧术语的时候。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-06
    • 2014-10-18
    • 1970-01-01
    • 2016-11-06
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多