两个 64 位数字相乘的问题

问题描述 投票:0回答:2

我想将两个 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);
时,问题就解决了。

  1. 我的问题是,这个数字1从哪里来?
  2. 我的错误是什么?
  3. 我该如何修改这个程序?

这个问题对我来说是一个严峻的挑战,我很感谢我的朋友们在这件事上指导我。

algorithm assembly x86 multiplication
2个回答
3
投票

您跳过了对源代码的注释。

第二个“中间子产品”的添加可能会产生你不计算在内的进位。


第二个“中间子乘积”的加法不会生成两个较大数字的进位(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

2
投票

@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]));
© www.soinside.com 2019 - 2024. All rights reserved.