[英]Adding 32-bit numbers on a 32 machine, widening to a 64-bit sum in two registers
如何在 32 位機器上添加幾個 32 位數字但沒有精度損失,即在 64 位“偽寄存器” eax:edx
。 使用英特爾語法匯編器。
假設您添加的 32 位數字在 EAX 和 EBX 中,並且是無符號的:
xor edx,edx ;Set edx to zero
add eax,ebx
adc edx,0 ;edx:eax = eax + ebx
這與在加法之前將值零擴展到 64 位,然后進行 64 位加法基本相同。
對於有符號整數,這將不起作用(例如“0 + (-1) != 0x00000000 + 0xFFFFFFFF != 0x00000000FFFFFFFF”),因為您需要進行符號擴展而不是零擴展。 要做到這一點:
cdq ;Set all bits in edx to the sign of eax
xchg ebx,eax ;eax = original ebx
mov ecx,edx ;ecx:ebx = original eax sign extended
cdq ;edx:eax = original ebx sign extended
add eax,ebx
adc edx,ecx ;edx:eax = eax + ebx
“可能更慢取決於它是哪個 CPU”(見注釋)替代方法是通過向它們添加 0x80000000 來強制它們進入無符號整數范圍,然后通過從中減去 2*0x80000000(或 0x0000000100000000)來糾正結果。 減去0x0000000100000000和high dword減1是一樣的,和high dword加0xFFFFFFFF是一樣的,所以可以是:
add eax,0x80000000
add ebx,0x80000000
xor edx,edx ;Set edx to zero
add eax,ebx
adc edx,0xFFFFFFFF ;edx:eax = eax + 0x80000000 + ebx + 0x80000000 + (-0x0000000100000000)
注意:如果你關心性能; 這種替代方法使您有機會將 0x80000000 添加到早期代碼中的值(無論值來自何處),並且通常可以更快地結束(特別是如果多次使用相同的 32 位值,和/或添加可以免費合並到其他計算中)。
對於“混合類型”,您只需要將有符號值提升為 64 位。 例如,如果 EAX 是有符號的而 EBX 是無符號的:
cdq ;Set all bits in edx to the sign of eax
add eax,ebx
adc edx,0 ;edx:eax = eax + ebx
當然,對於較新的 CPU,您將使用 64 位代碼。 對於無符號的 32 位值,默認情況下它們已經被零擴展,您只需要一個add rax,rbx
指令。 對於已簽名的數字,您可能需要簽署擴展(如果您不能/未事先簽署擴展它們),例如:
movsx rax,eax
movsx rbx,ebx
add rax,rbx
如果我正確理解了這個問題,您將有兩個 32 位整數,您可以將它們相加以得到一個 64 位整數。 您希望在沒有 32 位溢出的情況下執行此操作。
看看編譯器做了什么:
$ cat add64.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main (int argc, char **argv) {
uint32_t a, b;
a = strtoll(argv[1], NULL, 10);
b = strtoll(argv[2], NULL, 10);
printf("%lu + %lu = %llu\n", a, b, (uint64_t) a + b);
return 0;
}
$ gcc -m32 -g -o add64 add64.c
$ ./add64 3000000000 4000000000
3000000000 + 4000000000 = 7000000000
$ gcc -m32 -g -fverbose-asm -masm=intel -S add64.c
$ $EDITOR add64.s &
[5] 340
$
相關生成的程序集是:
mov %ecx, DWORD PTR [%ebp-16] # D.2300, a
mov %ebx, 0 # D.2300,
mov %eax, DWORD PTR [%ebp-12] # D.2301, b
mov %edx, 0 # D.2301,
add %eax, %ecx # D.2302, D.2300
adc %edx, %ebx # D.2302, D.2300
為了在 32 位機器上添加 64 位數字,您必須首先將 64 位數字的上半部分移入寄存器 eax,然后將下半部分移入 edx。 操作此數字時,您必須跟蹤該數字在 eax/edx 中的放置方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.