2013-03-23 66 views
1

我首先在C++中創建了一個類似的程序,然後我決定嘗試用x86彙編語言(我在大學裏教過的程序集類型)編寫它。我已經完成了C++版本,並且我的程序集版本幾乎完成了。GCD/LCM x86 Intel NASM彙編程序中的LCM計算錯誤

我在兩個版本上做了一些桌面檢查,第一次使用(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 
+0

你用調試器單步執行代碼嗎? – nrz 2013-03-23 22:22:46

+0

是的,我有。問題在於LCM計算,我確實得到了所有測試用例的正確分紅和除數。當使用更大的數字時,似乎事情出現了問題,我仍然認爲我的變量初始化和註冊使用有問題。 – Jamal 2013-03-23 22:27:53

+0

我把它回滾到最後一次編輯,因爲根據收到的答案修正問題的錯誤是沒有意義的。如果基本內容(問題中的錯誤)得到修復,這個問題對於未來的讀者來說變得毫無意義。 – nrz 2013-03-24 00:10:35

回答

3

的問題是在calc_lcm程序:

 
     mov BX, [gcd] 
     div BX 

     mov SI, AX 
     mov [lcm], SI 

num1爲19200和num2是8200,gcd變成200.在這裏,你試圖通過將產品計算LCM(19200,8200)的num1num2(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 
+0

我曾嘗試使用32位寄存器的div,但程序仍然崩潰。要麼我必須在其他地方進行更改,否則我無法在32位模式下使用這些數字(因此我無法使用64位寄存器)。 – Jamal 2013-03-23 23:32:55

+0

好的,gotcha。即使是32位分區,我仍然遇到崩潰。問題在其他地方嗎?或者我無法將32位數字除以另一個32位數字? – Jamal 2013-03-23 23:42:16

+0

您需要將'edx'歸零,因爲'edx:eax'被除數爲32位的除數,如'div ebx'。 – nrz 2013-03-23 23:51:34