assembly 两个64位数字相乘时出现问题

s3fp2yjn  于 2023-08-06  发布在  其他
关注(0)|答案(2)|浏览(121)

我想将两个64位无符号数相乘,并将结果存储在一个128位变量中。我是按照链接www.example.com中给出的方式做的https://www.plantation-productions.com/Webster/www.artofasm.com/Windows/HTML/AdvancedArithmetica2.html#1007619,迈克尔·伯尔在回答川原的问题(How can I multiply two 64-bit numbers using x86 assembly language?)时提到了这一点。下面是我的代码:

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;

字符串
运行程序后,此代码准确地回答两个较小的上限数的乘积
(in在这种情况下,确切的答案是:44CED55C313E2724C1798E86D8EE8890)但对于下面两个较大的数字,答案与精确值相差甚远
(in在这种情况下,确切的答案是:FFFFFFFFFFFFFE000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
但是当我将最后一个adc(0,edx);更改为adc(1,edx);时,问题就解决了。
1.我的问题是,这个数字1是从哪里来的?
1.我错在哪里?
1.如何修改此程序?
这个问题对我来说是一个严峻的挑战,我很感谢我的朋友们在这件事上指导我。

nkhmeac6

nkhmeac61#

您跳过了注解源代码。
第二个“中间子产品”的增加产生了一个你不考虑的进位。
通常,任一加法都可以生成进位:只是处理它们。
第二个“中间子积”的加法不会为两个更大的数字生成进位(Hashem alizadeh)
它应该:
FFFF FFFF×FFFF FFFF = FFFF FFFE 0000 0001     

hi×hi               lo×lo  
FFFF FFFE 0000 0001 FFFF FFFE 0000 0001   lower half never needs to be touched
no carry→ FFFF FFFE 0000 0001             1st add of middle sub-product, say, hi×lo
_____________________________
FFFF FFFE FFFF FFFF FFFF FFFF
   carry→ FFFF FFFE 0000 0001             2nd add of middle sub-product, say, lo×hi
_____________________________
FFFF FFFF FFFF FFFE 0000 0000

字符串

b0zn9rqh

b0zn9rqh2#

@greybeard是对的,因为第二个叉积的加法产生了另一个进位。研究99 * 99相乘产生9801的类似(十进制)情况。
FFFF FFFF乘以FFFF本身得到FFFF FFFE 0000 0001(类似于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]));

相关问题