使用 32 位算术添加 64 位数字
我们如何使用 32 位算术将两个 64 位数字相加?
How do we add two 64 bit numbers using 32 bit arithmetic??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我们如何使用 32 位算术将两个 64 位数字相加?
How do we add two 64 bit numbers using 32 bit arithmetic??
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(6)
首先添加最低有效字节,保留进位。考虑到 LSB 的进位,添加最高有效字节:
Add the least significant bytes first, keep the carry. Add the most significant bytes considering the carry from LSBs:
考虑如何使用一位数算术将两个两位数相加。
首先添加右列。 (“个”或“单位”)。 2+9 是 11。11“溢出”了您的 1 位算术,因此您必须“进位”10。
现在您将左侧的“十”列相加,包括进位。 1+4+3=8。
8 小于 10,所以没有进位。你完成了。
刚刚发生了什么?当你说一个数字是“42”(以 10 为基数)时,你真正的意思是
或者,等效地,
(当我说“a^b”,如“10^1”时,我的意思是“a 的 b 次方” “:a乘以自身b次。10^0是1。10^1是10。10^2是10*10=100...)
当你添加“42”和“39”时,你说的
是哪个等于
现在由于“11”不是有效的一位数字,因此您需要从个位中进位 10,将其转换为十位上的 1。
也就是 81。
那么,为什么我一直在谈论这个而不是你关于 64 位数字和 32 位算术的问题?因为它们实际上是一模一样的!
数字的范围是 0 到 9。“32 位数字”的范围是 0 到 2^32-1。 (假设它是无符号的。)
因此,我们不要使用基数 10,而是使用基数 2^32。在基数 2^32 中,我们将 2^32 写为 10。如果在基数 2^32 中写一个 64 位数字,则
x 和 y 是 0 到 2^32-1 之间数字的符号。这些符号是位串。
如果您想将两个 64 位数字相加,请以 2^32 为基数将它们分解为:
现在,以 2^32 为基数将它们相加,就像以 10 为基数相加一样,只是,而不是使用数字算术相加使用 32 位算术进行加法!
如何将一个 64 位数字 a 拆分为两个 32 位数字 a_1 和 a_0?将 a 除以 2^32。不是浮点数,而是整数——你可以得到被除数和余数。被除数为a_1,余数为a_0。
不幸的是,这需要 64 位算术。然而,通常 a_1 是 a 的“最重要的一半”,因此,在 C 风格语法中
:是右位移位并且 &是按位和。
通常,如果您无法进行 64 位加法,则“64 位数字”实际上是两个 32 位数字 a_1 和 a_0。如果你不能进行 uint64_t 算术,你就不会有 uint64_t!
所有这些都假设您正在执行无符号算术,但从这里处理符号很容易。
Consider how you add two 2-digit numbers using 1-digit arithmetic.
First you add the right column. (The "ones" or "units"). 2+9 is 11. 11 "overflowed" your 1 digit arithmetic, so you have to "carry" the 10.
Now you add up the left "tens" column, including the carry. 1+4+3=8.
8 is less than 10, so no carry. You're done.
What just happened? When you say that a number is "42" (in base 10) you really mean
Or, equivalently,
(when I say "a^b", like "10^1", I mean "a raised to the b'th power": a multiplied by itself b times. 10^0 is 1. 10^1 is 10. 10^2 is 10*10=100...)
When you add "42" and "39" you are saying
Which equals
Now since "11" isn't a valid one digit number, you need to carry 10 from the ones, turning it into a 1 in the tens place.
which is 81.
So, why have I been talking about this rather than your question about 64 bit numbers and 32 bit arithmetic? Because they are actually exactly the same!
A digit ranges from 0 to 9. A "32 bit number" ranges from 0 to 2^32-1. (Assuming it is unsigned.)
So, rather than working in base 10, let's work in base 2^32. In base 2^32, we write 2^32 as 10. If you write a 64 bit number in base 2^32, it would be
where x and y are symbols for numbers between 0 and 2^32-1. Those symbols are bitstrings.
If you want to add two 64 bit numbers, break them down in base 2^32 as:
Now you add them in base 2^32 the exact same way you add them in base 10 -- just, rather than adding using digit arithmetic you add using 32 bit arithmetic!
How do you split a 64 bit number a into two 32 bit numbers a_1 and a_0? Divide a by 2^32. Not in floating point, but integerwise -- where you get a dividend and a remainder. The dividend is a_1, the remainder is a_0.
Unfortunately that requires 64 bit arithmetic. However, typically a_1 is the "most significant half" of a, so, in C style syntax:
where >> is a right bitshift and & is bitwise and.
Typically if you can't do 64 bit addition, a "64 bit number" will actually be the two 32 bit numbers a_1 and a_0. You won't have a uint64_t if you can't do uint64_t arithmetic!
All this assumes that you're doing unsigned arithmetic, but dealing with signs is easy from here.
之前发布的 C 代码不必要地冗长:
“if”中的“a1”也可以替换为“b1”。
溢出时,c1 将小于 a1 和 b1。
The C code previously posted is unnecessarily verbose:
The 'a1' in the 'if' can be replaced with 'b1' as well.
On overflow, c1 will be less than both a1 and b1.
如果 64 位数字是 (a2,a1) 和 (b2,b1) ,其中 x2 是取为无符号的高 32 位,x1 是取为无符号的低 32 位作为无符号,则两个数字的总和如下所示。
If the 64-bit numbers are (a2,a1) and (b2,b1), where x2 is the high 32 bits taken as unsigned, and x1 is the low 32 bits taken as unsigned, then the sum of the two numbers is given below.
看起来像这样
实际硬件并不使用 32 位一次添加 16 位,加法只需要一位额外的进位,并且几乎所有 CPU 都有一个加法操作溢出时的进位状态标志,所以如果您使用的是 32 位 cpu,则可以在两个 32 位操作中添加 64 位操作数。
it looks something like this
Actual hardware doesn't use 32 bits to add 16 bits at a time, only one extra bit of carry is ever needed for addition, and almost all CPU's have a carry status flag for when an addition operation overflowed, so if you are using a 32 bit cpu, you can add 64 bit operands in two, 32 bit operations.
几乎每个处理器都有进位位和进位相加操作,只有在进行汇编编程时您才会关心这些操作。如果您使用的是高级语言,编译器会转储完全相同的加进位操作。我的 AVR-GCC 在添加两个 16 位数字时给出了这个结果(AVR 是 8 位),但相同的概念也适用于更高的处理器。
给定数字位于寄存器 R1:R2 和 R3:R4 中:
结果存储到 R1:R2 中。
Pretty much every processor has the carry bit and add-with-carry operation, which you only care about if you're programming in assembly. If you're using a higher language, the compiler dumps out the exact same add-with-carry operations. My AVR-GCC gave me this when adding two 16-bit numbers--the AVR is 8-bit--but the same concepts would apply for higher processors.
Given the numbers are in registers R1:R2 and R3:R4:
The result is stored into R1:R2.