题
我们如何使用添加32位算术两个64位数字??
解决方案
第一添加至少显著字节,保持进位。添加考虑从最低有效位的进位的最显著字节数:
; x86 assembly, Intel syntax
; adds ecx:ebx to edx:eax
add eax, ebx
adc edx, ecx
其他提示
考虑如何使用添加1位的算术两个2位数字。
42
+39
---
首先,添加右侧立柱。 (其中“一”或“单元”)。 2 + 9是11。11“溢出”您的1位算术运算,所以你必须“携带” 10。
1
42
+39
---
1
现在你把左边的“十位”一栏,包括随身携带。 1 + 4 + 3 = 8。
1
42
+39
---
81
图8是小于10,所以进位。你就大功告成了。
刚刚发生了什么?当你说一个号码是“42”(在基体10)你真的是
4*10+2
或者,等价地,
4*10^1+2*10^0
(当我说“一个^ B”,如“10 ^ 1”,我的意思是“一个上升到b'th功率”:一个自乘b乘以10 ^ 0是1 10 ^ 1是10. 10 ^ 2是10×10 = 100 ......)
在添加 “42” 和 “39” 你说
4*10+2+3*10+9
其等于
(4+3)*10+(2+9)*1
(4+3)*10+(11)*1
(4+3)*10+(1*10+1)*1
现在,因为“11”是不是一个有效一位数,则需要从的那些携带10,将其变成1中的十位。
(4+3)*10+(1)*10+(1)*1
(4+3+1)*10+(1)*1
(8)*10+(1)*1
这是81。
那么,为什么我一直在谈论这个,而不是你的问题,约64位数字和32位的算术?因为他们实际上是完全一样的!
一个数字范围从0到9的“32比特数”的范围从0到2 ^ 32-1。 (假设它是无符号的。)
因此,而不是在基体10的工作,让我们在基座2 ^ 32工作。在基体2的32次方,我们写出2 ^ 32作为10.如果在基座2 ^ 32写一个64位的数,这将是
(x)*10+y
其中x和y是符号0和2 ^ 32-1之间的数字。这些符号是位串。
如果要添加两个64位的数,其分解在基体2 ^ 32为:
a_1*10+a_0
+b_1*10+b_0
现在你将它们添加在基地2 ^ 32你添加它们在基地10完全相同的方式 - 只是,而不是使用数字算术加入您添加使用32位运算
!如何分割一个64位的数为两个32位数字A_1和A_0?由2 ^ 32分割。不要在浮点,但integerwise - 你在哪里得到的股息和余数。被除数是A_1,余数是A_0。
不幸的是,需要64位算术。然而,典型地是A_1的“最显著一半”,所以,在C风格语法:
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
其中>>是右位位移和&是按位和
通常,如果你不能做64位加法,一个“64比特数”实际上是两个32位的数字和A_1 A_0。你不会有一个uint64_t中,如果你不能做到uint64_t中算术!
这一切都假定你正在做的无符号运算,但是处理的迹象是很容易从这里开始。
先前发布的C代码是不必要的冗长:
unsigned a1, b1, a2, b2, c1, c2;
c1 = a1 + b1;
c2 = a2 + b2;
if (c1 < a1)
c2++;
在“A1”的“如果”可与“B1”,以及代替。 上溢,C1将小于两个a1和b1。
如果该64位数字是(a <子> 2 子>,一个<子> 1 子>)和(b <子> 2 子>,B <子> 1 子>),其中 X <子> 2 子>取的高32位作为无符号,和 X <子> 1 子>是低作为无符号的32位,则两数之和在下面给出。
c1 = a1 + b1
c2 = a2 + b2
if (c1 < a1 || c1 < b1)
c2 += 1
它看起来像这样
/* break up the 64bit number into smaller, 16bit chunks */
struct longint {
uint16 word0;
uint16 word1;
uint16 word2;
uint16 word3;
};
uint16 add(longint *result, longint *a, longint *b)
{
/* use an intermediate large enough to hold the result
of adding two 16 bit numbers together. */
uint32 partial;
/* add the chunks together, least significant bit first */
partial = a->word0 + b->word0;
/* extract thie low 16 bits of the sum and store it */
result->word0 = partial & 0x0000FFFF;
/* add the overflow to the next chunk of 16 */
partial = partial >> 16 + a->word1 + b->word1;
/* keep doing this for the remaining bits */
result->word1 = partial & 0x0000FFFF;
partial = partial >> 16 + a->word2 + b->word2;
result->word2 = partial & 0x0000FFFF;
partial = partial >> 16 + a->word3 + b->word3;
result->word3 = partial & 0x0000FFFF;
/* if the result overflowed, return nonzero */
return partial >> 16;
}
实际的硬件不使用32位来一次增加16位,只有一个随身携带的额外位曾经需要另外,几乎所有的CPU有当加法运算溢出进位状态标志,因此,如果您使用的是32位的CPU,可以在两个32位操作添加64个操作数。
几乎每一个处理器有进位,并附加与携带的操作,你只在乎,如果你在汇编语言编程。如果您使用的是更高的语言,编译器转储出完全一样的附加与携带的操作。我的AVR-GCC给了我这个增加两个16位数字时 - 的AVR 8位 - 但相同的概念也适用于更高的处理器。
给出的数字是在寄存器R1:R2和R3:R4:
ADD R2,R4 ; first add the two low-bytes, result stored into R2
ADC R1,R3 ; then the two high-bytes and the carry bit, into R1
在结果存储到R1:R2