冰楓論壇

標題: 用組合語言求兩數的最大公因數 [打印本頁]

作者: ikj78i    時間: 7 小時前
標題: 用組合語言求兩數的最大公因數
底下的gcd_lcm.asm也是在Windows作業系統下的主控臺程式:
  1. .586
  2. .model  flat,stdcall
  3. option  casemap:none
  4. include    c:\masm32\include\windows.inc
  5. include    c:\masm32\include\kernel32.inc
  6. include    c:\masm32\include\user32.inc
  7. include    c:\masm32\include\shlwapi.inc     ;內含 StrToInt 的原型
  8. includelib c:\masm32\lib\shlwapi.lib
  9. includelib c:\masm32\lib\kernel32.lib
  10. includelib c:\masm32\lib\user32.lib
  11. ;*******************************************************************************
  12. .DATA
  13. hOut    DD      ?
  14. hIn     DD      ?
  15. dOut    DD      ?
  16. dIn     DD      ?
  17. n1      DD      ?       ;第一個整數
  18. n2      DD      ?       ;第二個整數
  19. gcd     DD      ?       ;最大公因數
  20. lcm     DD      ?       ;最小公倍數
  21. sBuffer DB      60h dup (0)
  22. sHint   DB      "請輸正整數:"
  23. szFmt   DB      "%u與%u的最大公因數是%u,最小公倍數是%u",0
  24. ;*******************************************************************************
  25. .CODE
  26. ;-------------------------------------------------------------------------------
  27. input   PROC
  28.   ;顯示「請輸正整數:」的提示文字,並讓使用者輸入數字
  29.         invoke  WriteConsole,hOut,OFFSET sHint,SIZEOF sHint,OFFSET dOut,0
  30.         invoke  ReadConsole,hIn,OFFSET sBuffer,12,OFFSET dIn,0
  31.   ;呼叫StrToInt把使用者輸入的數字變成數值。假如使用者輸入「123」,但在記憶體中
  32.   ;並不是123這個數值,而是31h、32h、33h,這是因為鍵盤輸入的是字元,在電腦中每個
  33.   ;字元(字元可視為一個字,也就是鍵盤上的英文母、阿拉伯數字等),都以一個數來表示
  34.   ;,阿拉伯數字的1是用十六進位的31h表示,阿拉伯數字的2是用十六進位的32h表示,依
  35.   ;此類推,其中的h代表此數為十六進位,b代表二進位,d代表十進位,若數字後沒這些
  36.   ;英文字代表十進位。StrToInt的功用就是把31h、32h、33h轉換為123。
  37.   ;StrToInt只有一個參數,就是這些文字的位址,轉換後結果存於EAX裏
  38.         invoke  StrToInt,OFFSET sBuffer
  39.         ret
  40. input   ENDP
  41. ;-------------------------------------------------------------------------------
  42. ;利用輾轉相除法求num1、num2的最大公因數。在invoke fnd_gcd,n1,n2之後,n1、n2會分別
  43. ;存於num1、num2內,在fnd_gcd副程式內,最好使用num1、num2。
  44. fnd_gcd PROC    num1:DWORD,num2:DWORD
  45.         mov     ecx,num1 ;輾轉相除法的過程是兩數相除後,如果有餘數,那麼下次的除數
  46.         mov     edx,num2 ;是這次的餘數,被除數是這次的除數,再進行除法,直到餘數為
  47.         cmp     ecx,edx  ;零為止,最後一次的除數就是最大公因數
  48.         jb      below   ;比較兩數何者較小
  49. again:  xchg    ecx,edx ;較小的當除數存於ECX,較大的當被除數存EDX
  50. below:  mov     eax,edx ;把被除數放在EAX
  51.         xor     edx,edx ;使EDX變為0
  52.         div     ecx     ;EAX除以ECX得商為EAX,餘數為EDX
  53.         or      edx,edx ;檢查餘數EDX是否為0
  54.         jnz     again   ;若不為零,還須再次進行除法,經過除法後,餘數(EDX)一定比除數(ECX)小
  55.         mov     eax,ecx ;若為零,傳回最後除數即為最大公因數
  56.         ret
  57. fnd_gcd ENDP
  58. ;-------------------------------------------------------------------------------
  59. main    PROC
  60.         invoke  GetStdHandle,STD_OUTPUT_HANDLE
  61.         mov     hOut,eax
  62.         invoke  GetStdHandle,STD_INPUT_HANDLE
  63.         mov     hIn,eax
  64.   ;輸入第一個整數,存於n1
  65.         call    input
  66.         mov     n1,eax
  67.   ;輸入第一個整數,存於n2
  68.         call    input
  69.         mov     n2,eax
  70.   ;計算n1、n2的最大公因數,存於gcd內
  71.         invoke  fnd_gcd,n1,n2
  72.         mov     gcd,eax
  73.   ;計算n1、n2的最小公倍數,存於lcm內
  74.         mov     eax,n1
  75.         mul     n2
  76.         div     gcd
  77.         mov     lcm,eax
  78.   ;wsprintf會根據szFmt字串的格式,把n1、n2、gcd、lcm存於sBuffer內。這四個數值會變
  79.   ;成數字字串。假設n1是123,那麼在sBuffer內是31h、32h、33h。szFmt內的%u代表無號數
  80.   ;,可以把無號數是為正數。wsprintf的傳回值是在sBuffer存入多少位元組,此位元組數
  81.   ;會放在EAX傳回
  82.         invoke  wsprintf,OFFSET sBuffer,OFFSET szFmt,n1,n2,gcd,lcm
  83.         invoke  WriteConsole,hOut,OFFSET sBuffer,eax,OFFSET dOut,0
  84.         invoke  ExitProcess,0
  85. main    ENDP
  86. ;*******************************************************************************
  87. END     main
複製代碼
把它存成gcd_lcm.asm,照下圖淡藍色字輸入指令組譯後,就可執行。
要注意,gcd_lcm並沒有檢查使用者輸入的數值大小所以輸入的數值太大時會出錯,兩數最好要小餘65000。



gcd_lcm.png (9.56 KB, 下載次數: 0)

最大公因數執行結果

最大公因數執行結果






歡迎光臨 冰楓論壇 (https://bingfong.com/) Powered by 冰楓