我想将两个 64 位无符号数相乘并将结果存储在 128 位变量中。我按照链接中给出的方式做到了https://www.plantation-products.com/Webster/www.artofasm.com/Windows/HTML/AdvancedArithmetica2.html#1007619迈克尔·伯尔(Michael Burr)在回应中提到了这一点Kawarazu 的问题(如何使用 x86 汇编语言将两个 64 位数字相乘?)。这是我的代码:
program exercise;
static
qw1:qword:= 956_3547_6850_2300_5452;//$84B8_8BF3_1E4E_3B0C
qw2:qword:= 956_3547_6850_2300_5452;//$84B8_8BF3_1E4E_3B0C
//qw1:qword:= 18_446_744_073_709_551_615;//$FFFF_FFFF_FFFF_FFFF
//qw2:qword:= 18_446_744_073_709_551_615;//$FFFF_FFFF_FFFF_FFFF
prd:lword :=0;
#include("Stdlib.hhf");
begin exercise;
mov((type dword qw1[0]),eax);
mul((type dword qw2[0]),eax);
mov(eax,(type dword prd[0]));
mov(edx,ecx);
mov((type dword qw1[4]),eax);
mul((type dword qw2[0]),eax);
add(ecx,eax);
mov(eax,ebx);
adc(0,edx);
mov(edx,ecx);
mov((type dword qw1[0]),eax);
mul((type dword qw2[4]),eax);
add(ebx,eax);
mov(eax,(type dword prd[4]));
adc(ecx,edx);
mov(edx,ecx);
mov((type dword qw1[4]),eax);
mul((type dword qw2[4]),eax);
add(ecx,eax);
mov(eax,(type dword prd[8]));
adc(0,edx);
mov(edx,(type dword prd[12]));
stdout.put(prd, " ",(type uns128 prd));
end exercise;
运行程序后,这段代码准确回答了两个较小的上位数字的乘积
(在这种情况下,确切的答案是:44CED55C313E2724C1798E86D8EE8890)
但对于较低的两个较大数字,答案与确切值相去甚远
(在这种情况下,确切的答案是:FFFFFFFFFFFFFFFE0000000000000001,但是程序得到的值是FFFFFFFEFFFFFFFE0000000000000001,第13个字节有差异)。
但是当我把最后一个
adc(0,edx);
改为adc(1,edx);
时,问题就解决了。
这个问题对我来说是一个严峻的挑战,我很感谢我的朋友们在这件事上指导我。
您跳过了对源代码的注释。
第二个“中间子产品”的添加可能会产生你不计算在内的进位。
第二个“中间子乘积”的加法不会生成两个较大数字的进位(Hashem alizadeh )
嗯,应该:
FFFFFFFF×FFFFFFFF = FFFFFFFE00000001
hi×hi lo×lo
FFFF FFFE 0000 0001 FFFF FFFE 0000 0001
no carry→ FFFF FFFE 0000 0001 1st add of middle sub-product, say, hi×lo
_______________________________________
FFFF FFFE FFFF FFFF FFFF FFFF 0000 0001
carry→ FFFF FFFE 0000 0001 2nd add of middle sub-product, say, lo×hi
_______________________________________
FFFF FFFF FFFF FFFE 0000 0000 0000 0001
@greybeard 是正确的,因为第二个叉积的相加会产生进一步的进位。研究 99 * 99 相乘产生 9801 的类似(十进制)情况。
FFFF FFFF 本身相乘得到 FFFFFFFE00000001(类似于 9 * 9 = 81)。
然后进行必要的添加:
FFFF FFFE 0000 0001 8 1
FFFF FFFE 0000 0001 8 1
----------------------------------- --------
FFFF FFFE FFFF FFFF 0000 0001 8 9 1
FFFF FFFE 0000 0001 8 1
----------------------------------- --------
1 FFFF FFFD 0000 0000 0000 0001 <carry> 1 7 0 1
FFFF FFFE 0000 0001 8 1
----------------------------------- --------
FFFF FFFF FFFF FFFE 0000 0000 0000 0001 9 8 0 1
您可以尝试下一个解决方案:
mov((type dword qw1[0]),eax);
mul((type dword qw2[0]));
mov(eax,(type dword prd[0]));
mov(edx,EBX);
xor(ecx,ecx);
xor(esi,esi);
mov((type dword qw1[4]),eax);
mul((type dword qw2[0]));
add(eax,ebx);
adc(edx,ecx);
mov((type dword qw1[0]),eax);
mul((type dword qw2[4]));
add(ebx,eax);
mov(eax,(type dword prd[4]));
adc(edx,ecx);
adc(esi,esi); <<< If further carry exists Then make ESI = 1
mov((type dword qw1[4]),eax);
mul((type dword qw2[4]));
add(ecx,eax);
adc(esi,edx);
mov(eax,(type dword prd[8]));
mov(edx,(type dword prd[12]));