程序随机停止,没有明显的原因

时间:2016-10-31 18:52:40

标签: assembly tasm dosbox

我正在尝试根据“3n + 1”理论制作汇编语言程序,如果数字是奇数,则乘以3并加1,或者如果是偶数,则除以2并继续运行直到到达数字1。该程序要求用户输入一个正整数然后运行3n + 1程序,一旦它达到1,它就会返回到开始(还没有完全找到帽子,因为我不断收到错误说“相对超出范围0021h”在程序运行时,当程序运行时,打印出序列中的每个数字(包括用户输入的数字)并继续运行直到打印1后,程序停止。是我已经多次检查我的代码并使用TASM命令在DosBox中成功组装它没有错误或警告。但是当我运行它时,程序似乎停止并且dosbox没有给我提示命令就像程序退出时一样。这是我的代码:

INCLUDE io.h

Cr        EQU  0DH       ; carriage return
Lf        EQU  0AH       ; line feed

TheStack  SEGMENT STACK
          DW   100H DUP (?)
TheStack  ENDS

Data      SEGMENT
Number    Dw   ?
Prompt1   DB   'Please enter the positive integer of your choice:  ', 0
String    DB   40 DUP (?)
New   DB   6 DUP (?), 0
Int2      DB   '2'

Data      ENDS

Code      SEGMENT
          ASSUME Cs:Code, Ds:Data

Start:    Mov Ax, SEG Data    ; Load Data Segment Number.
          Mov Ds, Ax

Prompt:   Output Prompt1      ; Prompt for first number.
          Inputs String, 40   ; Read the ASCII characters.    
      AToI String      
          Mov Number, Ax ;stops here i think
      atoi int2
      mov Ax, number
      xor cx,cx
loop1:    mov bx, 2
      mov cx, 1
      mov dx, 3
      div int2    
      cmp ah,1
      je isodd
      cmp ah,0
      je nextinst
      xor cx,cx
nextinst: mov ax, number
      div bx
      add ax, cx
      mov number, ax
      cmp ax, number
      Je loop2
      xor cx,cx
isodd:    mov ax, number
      mul dx
      add ax, cx
      mov number, ax      
      xor cx,cx
loop2:    itoa new, Ax
      output new
      mov Ax, number
          cmp Ax,1    ; Compare cx to the limit
          jg loop1   ; Loop while less or equal


Quit:     Mov Al, 0           ; Put return code of zero in Al.
          Mov Ah, 4CH         ; Put DOS function call in Ah.
          int 21H             ; Call DOS

Code      ENDS
          END  Start

这是非常令人沮丧的,因为我的所有循环似乎都正确设置并且已经对程序进行了不同的更改,迫切需要让它正常工作,但无济于事!感觉就像我在圈子里跑来跑去修理一些容易修复的东西。为了让程序正常工作,我需要做什么?我的代码会导致这种情况发生吗?或者这只是DOSbox的一个问题?

1 个答案:

答案 0 :(得分:0)

无论如何,出于教育原因,主循环可以这样写:

    ; ax = n (unsigned greater than 1)
Loop3n1:
    mov     bx,ax       ; copy n to bx
    shr     ax,1        ; divide by 2
    jnc     wasEven     ; CF set when odd from shr
    mov     ax,bx
    add     ax,bx
    add     ax,bx       ; ax = 3*n
    inc     ax          ; +1
wasEven:
    ; here ax = 3*n+1 (odd n), or n/2 (even n)

    ; display ax
    ; make sure ax value is preserved!

    cmp     ax,1
    ja      Loop3n1     ; if (1 < n), loop

    ; jump to start? (and how it will exit?)

你应该总是试着接近理论公式,通常不需要的东西,通常你的代码的一些重组将允许你删除它。

例如,在这里,我除以2并用单shr ax,1测试均匀度(整数在计算机中以位为单位编码,代表2的幂。所以移位&#34; 1&#34; in向左或向右的位使其有效地为* 2或/ 2,加上最低有效位将进入CF,用于测试数字是偶数/奇数。

如果数字是偶数,我就完成了,只需显示它并循环。

如果它很奇怪,我会从副本中恢复它 - 这是额外的非公式化的东西,这有时是不可避免的,但是你会想通过尝试做3 * n并错过n值来解决它(因为它已经是n / 2)。

然后我通过简单的n + n + n + 1做3n + 1而不打扰mul并破坏更多的寄存器。在性能方面,旧的8086-80486 CPU上的四条指令甚至会比mul更快。 (Pentium可能是第一个挑战它的人,但是再说一遍,因为386你可以使用32b模式而lea eax,[ebx*2+ebx+1]在单指令中执行3n + 1。)

将结果与1进行比较,以确定是否需要再次循环。

就是这样,这是你对任务的描述,而这几乎可以通过1:1将其写入ASM指令(当然,这通常需要几次尝试)和修剪/清理,重新分配寄存器和搜索不同的指令)。总是尝试尽可能直接写出所需的东西(&#34;任务&#34;指令),然后通过改变原来的&#34;任务&#34;来寻找 - 如何桥接它们之间的差距。在不可避免的情况下,与其他人合作的指示或一些帮助指示。

花一些时间尝试一些头脑中的组合,并回想起比你看到的第一个更多的可能性。