GCD / LCM x86英特尔NASM装配程序中的LCM计算错误

时间:2013-03-23 22:10:35

标签: assembly macros x86 nasm cpu-registers

我首先用C ++创建了一个类似的程序,然后我决定尝试用x86汇编语言编写它(我在大学里教授的程序集类型)。我已经完成了C ++版本,我的程序集版本已基本完成。

我对两个版本进行了一些桌面检查,首先使用(2400,3750)。我在两个版本中得到了相同的LCM结果,这很好。但是,当我使用更大的数字(19000,8200)时,我的汇编程序崩溃,而我的C ++版本显示正确的结果。在计算LCM时,我怀疑它与我的汇编变量大小和/或我的寄存器用于除法有关。

我通过输出被除数(第一个数字乘以第二个数字)和除数(GCD结果)来测试我的LCM计算(减去除法运算)。我得到了正确的测试结果,所以我认为我的注册使用有问题。我之前已经测试了我的GCD计算,因此不应该成为问题的一部分。

%include "macros.s"

.DATA

num_lbl:   DB   "> Numbers (2): ", 0
gcd_lbl:   DB   "*** GCD: ", 0
lcm_lbl:   DB   "*** LCM: ", 0

num1:   DD   0
num2:   DD   0

num1_cpy:   DD   0
num2_cpy:   DD   0

gcd:   DD   0
lcm:   DD   0

.CODE
.STARTUP

xor       EAX, EAX
xor       EBX, EBX
xor       ECX, ECX
xor       EDX, EDX
xor       EDI, EDI
xor       ESI, ESI

main:
     nwln
     nwln
     PutStr   num_lbl
     nwln
     nwln
     GetLInt   [num1]
     GetLInt   [num2]

     mov   EAX, [num1]
     mov   [num1_cpy], EAX
     mov   EBX, [num2]
     mov   [num2_cpy], EBX

     call   calc_euclidean
     call   calc_lcm

     nwln
     PutStr   gcd_lbl
     PutLInt   [gcd]
     nwln
     PutStr   lcm_lbl
     PutLInt   [lcm]
     nwln

     .EXIT

calc_euclidean:
               mov   EAX, [num2]
               cmp   EAX, 0
               jne   chk_swap

               mov   EAX, [num1]
               mov   [gcd], EAX

               ret

calc_lcm:
         mov   EAX, [num1_cpy]
         mov   EDX, [num2_cpy]
         mul   EDX

         mov   EDI, EAX

         xor   EBX, EBX

         mov   EDX, EDI
         shr   EDX, 16
         mov   EAX, EDI
         mov   BX, [gcd]
         div   BX

         mov   SI, AX
         mov   [lcm], SI

         ret         

chk_swap:
         mov   EAX, [num1]
         mov   EBX, [num2]
         cmp   EAX, EBX
         jl    swap

after_check:
            jmp   loop

swap:
     mov   EAX, [num1]
     mov   EBX, [num2]

     ; temp
     mov   ECX, [num2]

     ; num2 = num1
     ; num1 = temp
     mov   EBX, EAX
     mov   EAX, ECX

     mov   [num1], EAX
     mov   [num2], EBX

     jmp   after_check

loop:
     mov   EDX, [num1]
     shr   EDX, 16
     mov   EAX, [num1]
     mov   BX, [num2]
     div   BX

     mov   EDI, [num1]
     mov   ESI, [num2]
     mov   EDI, ESI
     mov   [num1], EDI
     mov   [num2], EDX

     jmp   calc_euclidean

1 个答案:

答案 0 :(得分:3)

问题出在calc_lcm程序:

         mov   BX, [gcd]
         div   BX

         mov   SI, AX
         mov   [lcm], SI

num1为19200且num2为8200时,gcd变为200.此处您尝试通过除以num1的乘积来计算lcm(19200,8200)和num2(19200 * 8200 = 157440000)gcd(200):

157440000 / 200 = 787200

编辑:修正了拼写错误。

787200不适合16位。您需要将代码转换为使用32位div而不是16位div来处理比现在更大的数字。

所以它会是:

修改:添加了代码。

xor    ebx,ebx   ; this you have already.
mov    bx,[gcd]
xor    edx,edx   ; zero edx, as edx:eax gets divided by ebx...
div    ebx       ; ...now.

mov    [lcm],eax ; store the lcm into memory