【问题标题】:Assembly GCD Coding Infinite Loop汇编 GCD 编码无限循环
【发布时间】:2014-11-12 07:30:47
【问题描述】:

我正在尝试制作一个用于查找 GCD 的汇编程序,接受两个整数,然后打印出 GCD。代码组装得很好,但是在提交两个整数后程序陷入了无限循环:

;Title - GCD

INCLUDE Irvine32.inc


.data

strA BYTE "Enter an integer A: ",0
strB BYTE "Enter an integer B: ",0
temp DWORD ?
finalStr BYTE "GCD of the two integers is: ",0



.code

main PROC

call Clrscr

mainLoop:
mov edx,OFFSET strA
call WriteString
call ReadInt
mov temp, eax
call Crlf

mov edx, OFFSET strB
call WriteString
call ReadInt        
mov ebx, eax
mov eax, temp
call Crlf

call GCD

mov edx, OFFSET finalStr
call WriteString
call WriteInt

call WaitMsg

jmp mainLoop

main ENDP

;-----------------------------------------------
abs PROC
; Computes the absolute value of a number.
; Receives: eax = the number
; Returns:  eax = absolute value of the number
;-----------------------------------------------
   cmp eax, 0                    ; see if we have a negative number
   jge done
   neg eax

done:
   ret
abs ENDP

;-----------------------------------------------
gcd PROC
; Finds Greatest Common Divisor of two integers
; Recieves: eax= int A , ebx = int B
; Returns eax = GCD
;-----------------------------------------------
call abs        ;takes absolute value of both registers
mov temp, eax
mov eax, ebx
call abs
mov eax, temp

cmp eax, ebx    ; making sure we divide the bigger number by the smaller
jz DONE     ; if numbers are equal, GCD is eax either way
jc SWITCH   ;swaps if ebx is larger then eax

mov edx, 0

SWITCH:         ;swaps values so eax is larger then ebx
mov temp, eax
mov eax, ebx
mov ebx, temp
mov edx, 0
jmp L1

L1:     ;divides until remainder is 0, then eax is GCD
div ebx
cmp edx, 0
jz DONE
mov eax, edx
jmp L1


DONE:
gcd ENDP

END main

我怎样才能摆脱这个循环?

【问题讨论】:

  • PROC gcd 没有返回。在DONE:gcd ENDP 之间插入ret。不要忘记在每次div 之前清除EDX。欧几里得算法的实现是错误的。

标签: loops assembly masm irvine32 greatest-common-divisor


【解决方案1】:

我直接看到一个问题:

call abs        ;takes absolute value of both registers
mov  temp, eax
mov  eax, ebx
call abs
mov  eax, temp

没有任何东西将abs-ed ebx 值移回ebx,它应该是:

call abs        ;takes absolute value of both registers
mov  temp, eax
mov  eax, ebx
call abs
mov  ebx, eax
mov  eax, temp

另一个问题,虽然与您的问题没有直接关系,但 x86 架构有 long 有一个 xchg 指令可以大大清理您的代码,特别是使用 @987654328 @。


想想这个序列:

cmp eax, ebx    ; making sure we divide the bigger number by the smaller
jz DONE     ; if numbers are equal, GCD is eax either way
jc SWITCH   ;swaps if ebx is larger then eax

mov edx, 0

SWITCH:         ;swaps values so eax is larger then ebx

您会发现SWITCH: 处的代码将运行无论哪个值更大。

你可以通过改变来解决这个问题:

jc   SWITCH   ; swaps if ebx is larger then eax

mov  edx, 0

进入:

jc   SWITCH   ; swaps if ebx is larger then eax

mov  edx, 0
jmp  L1

除此之外,我将建议实际运行该代码在您的头脑中,以了解它是如何工作的,但更重要的是,如何像机器一样思考你会成为一个更好的开发者。

从下表开始:

[temp]   eax      ebx      edx      <stack>
-------- -------- -------- -------- --------
?        ?        ?        ?        ?,

然后依次执行每一行,随着数据的变化填充列。

你最终会弄清楚问题出在哪里,你也会明白为什么有时只有曾经有这种方法调试的老家伙很多做得更好:-)

我会给你一个线索。密切关注edx,看看它是如何变化的,以及它可能如何影响某些其他指令,例如div,这可能取决于它是否为零。

【讨论】:

  • 谢谢!但是,我仍然卡在这个循环中。
  • 是的,@George,我还在调查 :-)
  • 是的,我只是在发布后注意到了一点,所以我在“mov edx,0”行下方添加了“jmp L1”,因此它跳过了开关,但是我仍然得到循环
  • @George:请参阅我的最终评论。 查看代码。 成为代码:-)
猜你喜欢
  • 2016-11-01
  • 1970-01-01
  • 2020-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多