我正在尝试解决一个简单的组装任务(TASM),即:
单词中有一个带范围的自然数,用该数字确定第二度的数字总和。
我想将添加的结果输出到DOS 6^2 + 1^2 + 3^2 + 1^2 + 3^2
。
下面的代码只能在DOS中输出数字,而没有更多信息,这是我们的讲师给定的。
;stack segments
stk segment stack
db 128 dup(?)
stk ends
;data segment
data segment para public 'data'
x dw 61313
DThousands dw ?
Thousands dw ?
Hundreds dw ?
Decades dw ?
Units dw ?
result dw ?
data ends
;command segment
code segment para public 'code'
assume cs:code, ds:data, ss:stk
begin:
mov ax, data
mov ds, ax
mov ax, x ; заносим число x в регистр ax
mov result, ax ; заносим в зарезервированный участок памяти result значение из ax
mov ax, result ; меняем значение
xor cx, cx ;MOV CX, 0
mov bx, 10 ; bx = 10
m_do_while:
xor dx, dx ; обнуление dx
div bx ; деление ax на bx
push dx ; заталкиваем dx в стек
inc cx ; увеличиваем cx на 1
cmp ax, 0 ; сравниваем регистр ax с нулем
jne m_do_while ; выполняем условный переход
mov ah, 2 ; помещаем в регистр ah 2
m_for:
pop dx ; достаем из стека значение dx
add dx, 30h ; прибавляем к dx 30h
int 21h ; системное прерывание
loop m_for ; цикл
back:
;end of program
mov ax, 4C00h
int 21h
code ends
end begin
通过该打印循环,你已经一次获得一位数字。加法是关联的,因此无论你按什么顺序来添加它们,都可以从最低有效数字开始添加。
digit_sum:
mov ax, x ; input in AX
mov bx, 10 ; base 10
xor cx, cx ; sum
.sumloop:
xor dx, dx
div bx ; quotient in AX, remainder (the digit) in DX
;; With 386
;imul dx, dx ; requires 386
;add cx, dx ; sum += digit^2
;; Without 386
xchg ax, dx
mul al ; result in AX. DX untouched. single-digit numbers fit in AL
add cx, ax ; sum += digit^2
mov ax, dx
test ax, ax
jne .sumloop
;;; sum in CX
ret
然后进行cx
有效打印,例如,从末尾开始将其转换为缓冲区,然后进行一个打印系统调用。(如何在不使用c库中的printf的汇编级编程中打印整数?)。我不建议你在问题中显示笨拙的push / pop 2-loop方法,但是它很流行并且确实有效。无论如何,mov ax, cx
将总和放入AX中。
你甚至可以像使用汇编程序8086那样使用除以10并推动的循环来获得一些代码重用。数组的总和,输出多位数的数字。第一次,使用它来获取要弹出的数字并平方->和。第二次,使用它生成总和的数字,然后弹出并打印。(但是编写一个在堆栈上留下可变数量东西的函数是棘手的;你可以在函数的开头弹出返回地址,然后进行push / ret。或者只是使其成为要使用两次的宏,因此可以内联两个地方。)
如果你想兼容8086,但要适应最新的Intel CPU(xchg
3 ups,因此成本与3 mov指令相同):xchg ax,dx
可以使用mov si, ax
/ mov ax, dx
,然后使用mul / add,然后使用代替mov ax, si
。对于实际的古代8086,xchg
它很棒:较小的速度更快(除了诸如mul和div之类的速度很慢的指令之外),xchg
-with-ax只有1个字节。
当然,如果你实际上关心速度,则可以使用乘法逆除以10。对于实际8086处mul
非常慢(但不如慢div
)的情况,则可以使用正方形的查找表来节省速度。那部分:
; given a digit in DX, add its square to CX, indexing a table of words
mov si, dx
shl si,1
add cx, [table + si]
或仅使用一个字节表,将1个额外的代码大小的字节换成一个较小的表,并减少1个字节的数据加载(在8088上达到收支平衡,除了预取差异外):
mov si, dx
add cl, [table + si]
adc ch, 0 ; carry to the high half of CX
我感到很尴尬,但是您可以编写一个完整的程序来输出金额吗?因为我的老师给我代码以在DO中输出数字,而没有说明它是如何工作的,我对于如何将代码与您的解决方案结合起来感到困惑
@Dsyder:不用了,我对为您完成家庭作业不感兴趣。此外,在AX中输入的情况下,您实际上已经具有可以输出数字的代码。如果您想了解重复的除以10的知识,请阅读我的答案,如何从c库中在没有printf的情况下在汇编级编程中打印整数?和/或仔细考虑会发生什么。 使用DOS显示数字的过程也很详细。
非常感谢,我能够将您的答案和我的代码结合起来,并且有效!不幸的是,我不能对你的回答表示支持:(但是,我非常感谢你