我正在尝试根据“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的一个问题?
答案 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;来寻找 - 如何桥接它们之间的差距。在不可避免的情况下,与其他人合作的指示或一些帮助指示。
花一些时间尝试一些头脑中的组合,并回想起比你看到的第一个更多的可能性。