将近 4 年之后,你没有得到这个问题的直接答案,这是你应得的。所以我们开始:
您无法获得浮点位,只需将它们相加即可获得结果的浮点数,它们不是十进制或十六进制数。
浮点数值系统让很多人感到害怕,它是一种表示数值的不同方式,对于用巨大或微观数字进行计算非常有用。我们在小学、中学、甚至大学都没有学到这一点。没有可以处理 FP 数字的袖珍卡西欧计算器,所以我们对这些不是很熟悉,而且我们都独自一人在黑暗中。
大多数程序员(如果不是全部)更愿意让 FP 由 C/C++ 编译器处理,他们不会按位接触 FP,对某些人来说它就像一场瘟疫。无论如何,FP是由人类创造的(真正的问题),即便如此,也有办法处理它。
我在这里的目的不是教你如何在 AVR 汇编中做到这一点,即使这完全有可能也很容易,如果你按照我下面的解释来做的话。我在这里的意图是表明“老虎”不是怪物,它是一只蓝眼睛的小宠物猫,但它仍然是一只长着牙齿和爪子的猫科动物。
您将在下面找到:
1. 浮点的核心
2. 简单的浮点乘法
3. 浮点加法(你的问题)
胆量:
是单精度和双精度 FP,32 位和 64 位,让我们剥离 32。
一个FP号码有3个区:

a) 符号,1 位,#32(左一),0 表示正,1 表示负。
b) 指数,8 位,这里是老虎打猎的地方,人们很困惑。
c) 尾数,23 位,指数小数补码。
为了能够表示一个非常大或非常小的数字,中心将为 1,因此,当指数的第 7 位(我们称之为“7E”)为 1 时,该数字为 1 或更大。7E=1 数字 >=1,7E=0 数字小于 1(例如 0.7)。
在考虑指数的位值时,您不需要将 7E 视为具有值的真实位,有些人会这样做。从现在开始,我们将只处理大于 1 和正数的数字,因此我不会评论 7E 或符号位,更不会将其视为指数的值。
指数和尾数是二进制计数的。Exponent 位的值与常规二进制数相同,不同之处在于位值总是加 1,E1=2,E2=3,E2+E1=4,E3=5……所有位E1 到 E6 开启 = 128。
Exponent 表示的值为 2^n,其中“n”是上述位或位组合的值。最小值是 2^-126 一个非常小的数字,最大值是 2^128 一个被认为是无穷大的巨大数字,2^127 有 39 位数字。
E7.6.5.4.3.2.1.0
1 0 0 0 0 0 0 0 = decimal 0, but remember, it needs to add 1, so it is 1, and the value is 2^1 = 2
E7.6.5.4.3.2.1.0
1 0 0 0 0 0 0 1 = decimal 1, +1 = 2, 2^2 = 4
1 0 0 0 0 0 1 0 = decimal 2, +1 = 3, 2^3 = 8
1 0 0 0 0 0 1 1 = decimal 3, +1 = 4, 2^4 = 16
1 0 0 0 0 1 0 0 = decimal 4, +1 = 5, 2^5 = 32
1 0 0 0 0 1 0 1 = decimal 5, +1 = 6, 2^6 = 64
1 0 0 0 0 1 1 0 = decimal 6, +1 = 7, 2^7 = 128
1 0 0 0 0 1 1 1 = decimal 7, +1 = 8, 2^8 = 256
1 0 0 0 1 0 0 0 = decimal 8, +1 = 9, 2^8 = 512
1 0 0 1 0 0 0 0 = decimal 16, +1 = 17, 2^17 = 131072
1 0 0 1 0 0 0 1 = decimal 17, +1 = 18, 2^18 = 262144
观察指数加 1 将其值乘以 2。
反之亦然,减去 1,将指数除以 2。
10000100 = 32,减去 1,变为 10000011 = 16。
此外,向左移动一位并加 1,将 Exponent 自身乘以 N^2。例如,10000010 = 8,左移 10000100 = 32,再加上 1 10000101 = 64 = 8^2。
因此,左移 = N * N/2。
仅当位 E1(指数的最后一位)为 1 时,反之才成立,10000101 (64) 减一并右移将得到平方根 10000010 (8)。10001011(4096)减一右移变为10000101 = 64。如果E1=0,结果无效,10000110(128)减一的情况,10000101右移变为10000010即8,如果只移位不减就变为10000011 即 16,均无效。
强化这个想法:
二进制中的 0000-1110 意味着 2^3 + 2^2 + 2^1 = 8 + 4 + 2 =
14。FP 中的 x000-1110 指数意味着 2^(2^3 + 2^2 + 2^ 1 + 1) = 2^(14+1) = 2^15 = 32768。
但是您会看到指数只能形成 2^n 的值,而不是中间值,例如 5、12、15、257 等。这就是尾数起作用的地方。它将指数的分数存储为 2^-n,其中“n”是尾数位值。
FP位23是尾数位1,所以它的值为2^-1,也就是1/2,也就是0.5。
FP 位 22 是尾数位 2,其值为 2^-2、1/4 或 0.25,依此类推。
当你在“n”上加上一个负号作为2的指数时,它与用这个值除1是一样的。2^3=8,2^-3=1/8。
但是尾数不是数字,它是指数的被乘数。比如FP bit 23 Mantissa M1 10000000...不是0.5,表示Exponent值应该加上自己的Half。为了更好地理解它,尾数 23 位都小于 1,它们是 0.nnnn。基于此,我们需要在其前面插入一个不可见的整数 1.,因此,尾数 1000000... 即 0.5 变为 1.5。这意味着指数必须乘以 1.5
因此,FP 0-10000001-1000000000.... 表示指数 4,乘以 Mantisse 1.5 = 6。
如果 FP 0-10000001-110000000... 表示 4 x (1 + 0.5 + 0.25) = 4 x 1.75 = 7
Bit 23 = 0.5 (left bit)
Bit 22 = 0.25
Bit 21 = 0.125
Bit 20 = 0.0625
Bit 19 = 0.03125
...
...
Bit 1 = 0.0000001192092896 (bit FP 1)
现在,相同的尾数 0.75 (1100000 ....) 将始终将指数乘以 1.75,无论它的值是多少。数字 6、12、24 共享相同的尾数“100000....”,即 0.5,因为它乘以 4x1.5=6、8x1.5=12、16x1.5=24 等。
这有什么重要性?
2. 简单的浮点乘法
看,如果你有两个数字,尾数相同,这意味着这两个数字将具有相同的小数被乘数。如果你想将这些数字相乘,只需乘以指数,除以向右移动的尾数。
例如,将 6 乘以 24。6
的 2^n 指数是 4,尾数是 0.5
24 的 2^n 指数是 16,尾数也是 0.5
那么,6 x 24 = 144,除以 1.5 再除以 1.5 = 64,也就是 4x16 。
因为有两个尾数,所以除以 1.5 的两倍,将与除以 144 / (1.5 * 1.5) = 144 / 2.25 = 64 相同。
因此,乘法结果的新尾数将为 0.5 * 0.5 = 0.25,或 0.5 / 2.
好奇,144的FP是多少?
0-10000110-0010000000000....
指数 10000110 是什么意思?右边的位 "000110" = 6 +1 = 7, 2^7=128
001000000... 的尾数是什么意思?1/8 或 0.125。
所以,128 * 1.125 = 144... 整洁。
6 的指数乘以 24 的指数如何变成 128 的指数?
6 的指数是 4 0-10000001-xxxxxxxxxx
24 的指数是 16 0-10000011-xxxxxxxxxx
Exponent 处的每个添加位意味着将其乘以 2
因此,将位添加到 16 的 Exponent 将 1000-0011 变为 1000-0100 (32)。
我们需要将 16 乘以 4,我们需要添加 2 位,它将从 1000-0011 变为 1000-0100(第一位)然后变为 1000-0101(第二位)= 64。
由于两个尾数相同,只需将它向右移动与指数乘法相同数量的位,即 2 位。
从 100000000... 到 001000000...
然后,将“6” FP 0-10000001-1000000... 乘以“24” FP 0-10000011-1000000... 的结果 FP 为 144 FP 0-10000101-0010000000 ... 指数 = 128 乘以尾数 1.125 = 144。
如果尾数不同,则技术不同。
3.浮点加法(你的问题)
让我们首先添加简单的数字,6 和 8 = 14
6 = FP 0-10000001-1000000000...
8 = FP 0-10000010-0000000000....
14 = FP 0-10000010-1100000000....
14 的指数是它的下整数 2^n,即 8
14 的尾数是 8 的分数,它试图组成差值
6。6/8 = 0.75,即 0.5 + 0.25 的组成
所以, 14 的尾数将是 11000000000....
但它是如何以二进制形式发生的?
有规则。
首先,如果第一个指数小于第二个指数,则减去并取绝对差(AD)并右移小数尾数的 AD 位。
6 的指数是 10000001,8 的指数是 10000010,差是 1,所以将 6 的尾数右移一位。记住尾数 10000.... 是 0.5,但实际上是 1.5,所以有这个不可见的整数 1 . 现在你需要在两个尾数前面插入这个 1,并将 6 位的尾数右移一位,区别。
尾数 6 和 1. = 1.10000000....
尾数 8 和 1. = 1.00000000....
6 的尾数右移 1 位 = 0.110000000
8 的尾数仍然相同 = 1.000000000
现在添加两者
0.1100000000
1.0000000000
--=--------- +
1.1100000000
现在,重要的是整数 1. 必须正好在那个位置,它不能在左边 (1x.xxxxx...) 或在它的位置上为零。如果发生这种情况,有一些技术可以解决这个问题。
现在,原来的整数 1.xxx 消失了,反正是不可见的,最后的尾数变成了 110000000....
新的指数将更大,在这种情况下是 8 的指数,10000010
。这是规则,当有一个更大的指数或尾数的加法不以大于 1 的整数结束时,新的指数是和更大的一样。如果加法结果的整数大于 1,则为 2 (10.xxxx~),然后只需将指数加 1,并将整个结果尾数右移一位,即为 1.xxxx~。我在这篇文章的末尾举了一个例子。
现在只需复合指数 + 尾数:
0-10000010-11000000... 是 14 的 FP,加上 6 + 8。
您可以单独在下面添加您自己的 FP 号码吗?
Your number A = 5.1243230 FP 0-10000001-01000111111101001110100
your number B = 2.2134523 FP 0-10000000-00011011010100100110100
Result A + B = 7.3377753 FP 0-....
A 指数 = 4, 10000001
B 指数 = 2, 10000000
它们之间的差是 1
所以,在两个尾数前面加上整数 1,然后将 B 的尾数右移 1 位。
A = 1.01000111111101001110100
B = 1.00011011010100100110100
右移 1 位 B
A = 1.01000111111101001110100
B = 0.10001101101010010011010
添加两者
A = 1.01000111111101001110100
B = 0.10001101101010010011010
------------------------------ +
1.11010101100111100001110
整数继续 1,完美。
现在,消除整数并使用此尾数作为结果
与较大的指数连接,即 4,10000001 变为
FP = 0-10000001-1101010110011110000111000...
这正是 7.3377753 的 FP。
(以下是后来添加
的)添加结果尾数与位 10.xxxx 的示例~
假设您要添加 7 + 2 = 9
7 FP 0-10000001-11000~
2 FP 0-10000000-00000~
7 的指数大于 2,差为 1。所以让我们在两个尾数前面插入隐式整数 1:
7 Mantissa: 1.110000~
2 mantissa: 1.000000~
将较小的 (2) 尾数右移一位并将两者相加。
7 Mantissa: 1.110000~
2 mantissa: 0.100000~
----------------------- +
Resulting: 10.010000~
看,有一个 2(位 10.xxx~)作为结果尾数的隐式整数。如前所述,这个隐含的 1 代表一次指数。现在,这 2(位 10.xx~)代表指数的两倍。我们需要将这个额外的 ONE 时间转移回指数,将指数加 1,这实际上是将指数乘以 2。这样做,我们需要将尾数除以 2,将其右移一位。
因此,得到的尾数 10.010000~ 将变为 1.001000~
最终 FP 将是 0-10000010-0010000~ 即 9。
容易,不是吗?
现在让我们在 Assembly AVR 中执行此操作,每个 FP 仅使用 4 个寄存器(32 位),另外 4 个寄存器用于答案(感谢 Peter 发现“3”错字)。