C++ 浮点加法(从头开始):无法计算负结果
C++ Floating Point Addition (from scratch): Negative results cannot be computed
我正在按照此 PDF 中列出的方法从头开始实施浮点加法程序:https://www.cs.colostate.edu/~cs270/.Fall20/resources/FloatingPointExample.pdf
我遇到的主要问题是,当结果为正时加法有效 (e.x.-10 + 12, 3 + 5.125),但当结果为负时加法无效。这是因为不明白如何实现下面的步骤:
Step 5: Convert result from 2’s complement to signed magnitude
If the result is negative, convert the mantissa back to signed magnitude by inverting the bits and adding 1. The result is
positive in this example, so nothing needs to be done.
如何在不使用浮点加法的情况下判断结果是否为负(不允许使用任何浮点加法或双加法)?当然,我可以查看当前和下一个浮点数是否为负数并查看它们的累积数量,但这会破坏此作业的目的。
如果给出只有以下:
- X 的符号位、指数和尾数
- Y 的符号位、指数和尾数
- Z 的尾数和指数
如何仅使用上述数据而不使用任何浮点加法来确定 Z = X + Y
是否为负数?
在第 5 步,您已经添加了尾数。要确定结果是正数还是负数,只需检查该和的符号位即可。
如果您正在关注您发布的 PDF,您应该已经在第 3 步 将数字转换为 2 的补码。在 第 4 步 中进行加法后,您将得到 2 的补码结果。 (添加移位数字的结果)
要检查结果是否为负,您需要检查结果位模式中最左边的位(符号位)。在 2 的补码中,负数为 1,非负数为 0。
sign = signBit;
if (signBit) {
result = ~result + 1;
}
如果您使用无符号整数来保存位模式,您可以将它们设为固定大小,以便稍后可以使用移位找到符号位。
uint64_t result;
...
signBit = (result >> 63) & 1;
关键是许多浮点格式将符号和尾数分开,因此尾数是 无符号 整数。符号和尾数可以简单地组合起来创建一个 signed 整数。然后,您可以使用带符号的整数算术来加减浮点数的两个尾数。
小学数学和我们用浮点数所做的唯一区别是我们有二进制补码(以 2 为底与以 10 为底并不真正相关,只是让生活更轻松)。所以如果你读完了小学,你就会知道这一切是如何运作的。
在小学的小数中,你对齐小数点然后做数学。对于浮点数,我们移动较小的数字并丢弃它的尾数(抱歉分数)位以将其与较大的数字对齐。
在小学,如果做减法,一旦你解决了身份问题,你就会从较大的数字中减去较小的数字
a - (-b) = a + b
-a + b = b - a
等等,这样你要么有
n - m
或
n + m
然后你算算。根据获得 a-b 或 a+b 所必须做的事情应用符号。
二进制补码的美妙之处在于,否定或否定是反转并加一,这很好地融入了逻辑。
a - b = a + (-b) = a + (~b) + 1
所以你不重新安排操作数,但你可能不得不否定第二个。
你也不必记住结果的符号结果告诉你它
签名。
所以对齐点
把它放在表格
a + b
a + (-b)
其中a可以是正数也可以是负数但是b的符号和操作可能需要
否定 b.
做加法。
如果结果为负,则将结果取反为正
标准化
IEEE 只参与希望 1.fraction 为正数,其他浮点格式允许负数 whole.fraction 并且不求反,简单
正常化。剩下的只是小学数学(加上二进制补码)
一些例子
2 + 4
二进制数是
+10
+100
转换为规范化形式的是
+1.0 * 2^1
+1.00 * 2^2
需要相同的指数(对齐点)
+0.10 * 2^2
+1.00 * 2^2
两者都是正数所以没有变化只是做加法
这是基本形式,我在前面放了比需要更多的符号扩展名
使结果的符号更容易看到。
0
000010
+000100
=======
填写
000000
000010
+000100
========
000110
结果为正(结果的 msbit 为零)所以归一化
+1.10 * 2^2
4+5
100
101
+1.00 2^2
+1.01 2^2
同指数
均为阳性
0
000100
+000101
=======
001000
000100
+000101
=======
001001
结果为阳性,因此归一化
+1.001 * 2^3
4 - 2
100
10
+1.00 * 2^2
+1.0 * 2^1
需要相同的指数
+1.00 * 2^2
+0.10 * 2^2
减去 a - b = a + (-b)
1 <--- add one
00100
+11101 <--- invert
=======
填写
11011
00100
+11101
=======
00010
结果为阳性,因此归一化
+1.0 * 2^1
2 - 4
10
100
+1.0 * 2^1
+1.00 * 2^2
取相同的指数
+0.10 * 2^2
+1.00 * 2^2
算一下
a - b = a + (-b)
1
000010
+111011
========
填写
000111
000010
+111011
========
111110
结果为负,因此取反 (0 - n)
000011 <--- add one
000000
+000001 <--- invert
=========
000010
正常化
-1.0 * 2^1
我正在按照此 PDF 中列出的方法从头开始实施浮点加法程序:https://www.cs.colostate.edu/~cs270/.Fall20/resources/FloatingPointExample.pdf
我遇到的主要问题是,当结果为正时加法有效 (e.x.-10 + 12, 3 + 5.125),但当结果为负时加法无效。这是因为不明白如何实现下面的步骤:
Step 5: Convert result from 2’s complement to signed magnitude
If the result is negative, convert the mantissa back to signed magnitude by inverting the bits and adding 1. The result is
positive in this example, so nothing needs to be done.
如何在不使用浮点加法的情况下判断结果是否为负(不允许使用任何浮点加法或双加法)?当然,我可以查看当前和下一个浮点数是否为负数并查看它们的累积数量,但这会破坏此作业的目的。
如果给出只有以下:
- X 的符号位、指数和尾数
- Y 的符号位、指数和尾数
- Z 的尾数和指数
如何仅使用上述数据而不使用任何浮点加法来确定 Z = X + Y
是否为负数?
在第 5 步,您已经添加了尾数。要确定结果是正数还是负数,只需检查该和的符号位即可。
如果您正在关注您发布的 PDF,您应该已经在第 3 步 将数字转换为 2 的补码。在 第 4 步 中进行加法后,您将得到 2 的补码结果。 (添加移位数字的结果)
要检查结果是否为负,您需要检查结果位模式中最左边的位(符号位)。在 2 的补码中,负数为 1,非负数为 0。
sign = signBit;
if (signBit) {
result = ~result + 1;
}
如果您使用无符号整数来保存位模式,您可以将它们设为固定大小,以便稍后可以使用移位找到符号位。
uint64_t result;
...
signBit = (result >> 63) & 1;
关键是许多浮点格式将符号和尾数分开,因此尾数是 无符号 整数。符号和尾数可以简单地组合起来创建一个 signed 整数。然后,您可以使用带符号的整数算术来加减浮点数的两个尾数。
小学数学和我们用浮点数所做的唯一区别是我们有二进制补码(以 2 为底与以 10 为底并不真正相关,只是让生活更轻松)。所以如果你读完了小学,你就会知道这一切是如何运作的。
在小学的小数中,你对齐小数点然后做数学。对于浮点数,我们移动较小的数字并丢弃它的尾数(抱歉分数)位以将其与较大的数字对齐。
在小学,如果做减法,一旦你解决了身份问题,你就会从较大的数字中减去较小的数字
a - (-b) = a + b
-a + b = b - a
等等,这样你要么有
n - m
或
n + m
然后你算算。根据获得 a-b 或 a+b 所必须做的事情应用符号。
二进制补码的美妙之处在于,否定或否定是反转并加一,这很好地融入了逻辑。
a - b = a + (-b) = a + (~b) + 1
所以你不重新安排操作数,但你可能不得不否定第二个。 你也不必记住结果的符号结果告诉你它 签名。
所以对齐点 把它放在表格
a + b
a + (-b)
其中a可以是正数也可以是负数但是b的符号和操作可能需要 否定 b.
做加法。
如果结果为负,则将结果取反为正
标准化
IEEE 只参与希望 1.fraction 为正数,其他浮点格式允许负数 whole.fraction 并且不求反,简单 正常化。剩下的只是小学数学(加上二进制补码)
一些例子
2 + 4
二进制数是
+10
+100
转换为规范化形式的是
+1.0 * 2^1
+1.00 * 2^2
需要相同的指数(对齐点)
+0.10 * 2^2
+1.00 * 2^2
两者都是正数所以没有变化只是做加法
这是基本形式,我在前面放了比需要更多的符号扩展名 使结果的符号更容易看到。
0
000010
+000100
=======
填写
000000
000010
+000100
========
000110
结果为正(结果的 msbit 为零)所以归一化
+1.10 * 2^2
4+5
100
101
+1.00 2^2
+1.01 2^2
同指数 均为阳性
0
000100
+000101
=======
001000
000100
+000101
=======
001001
结果为阳性,因此归一化
+1.001 * 2^3
4 - 2
100
10
+1.00 * 2^2
+1.0 * 2^1
需要相同的指数
+1.00 * 2^2
+0.10 * 2^2
减去 a - b = a + (-b)
1 <--- add one
00100
+11101 <--- invert
=======
填写
11011
00100
+11101
=======
00010
结果为阳性,因此归一化
+1.0 * 2^1
2 - 4
10
100
+1.0 * 2^1
+1.00 * 2^2
取相同的指数
+0.10 * 2^2
+1.00 * 2^2
算一下
a - b = a + (-b)
1
000010
+111011
========
填写
000111
000010
+111011
========
111110
结果为负,因此取反 (0 - n)
000011 <--- add one
000000
+000001 <--- invert
=========
000010
正常化
-1.0 * 2^1