Assembly 打印整数的平方和(TASM)

Assembly 打印整数的平方和(TASM),assembly,x86-16,tasm,Assembly,X86 16,Tasm,我试图解决汇编(TASM)中的一个简单任务,即: 单词中有一个带范围的自然数,用这个数字确定二级数字的和 我想将添加6^2+1^2+3^2+1^2+3^2的结果输出到DOS 下面的代码只能在DOS中输出一个数字,不能再输出了,由我们的指导老师给出 ;stack segments stk segment stack db 128 dup(?) stk ends ;data segment data segment para public 'data' x dw 6131

我试图解决汇编(TASM)中的一个简单任务,即:

单词中有一个带范围的自然数,用这个数字确定二级数字的和

我想将添加
6^2+1^2+3^2+1^2+3^2
的结果输出到DOS

下面的代码只能在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   

首先,您必须将该数字除以10000,如果它>9999,则它将是您的第一个字符,然后将结果除以任何基址寄存器,并找到相同的下一个字符。

您的程序从
x
中获取二进制数,以十进制格式正确显示它:61313,然后返回:并结束。缺少计算数字平方的代码。
创建一个子过程,该子过程以
dx
中的一个二进制数字作为输入,将其与自身相乘,并将平方累加为
sum
。子过程不应碰撞任何寄存器:

SquareDX:     ; Let [sum] += DX*DX
     PUSH AX  
     PUSH DX
       MOV AX,DX
       MUL DX
       ADD [sum],AX   
     POP DX
     POP AX
     RET

之后调用子过程
pop-dx;dx

但在此之前
添加dx,30小时;Пибббббббббббббб


您需要做的最后一件事是以十进制表示法显示二进制
sum
,与显示二进制
x

完全相同您已经在打印循环中一次获得一个数字。加法是关联的,所以不管你把它们放在什么顺序,你都可以从最低有效数字开始加法

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
,例如,从末尾开始转换为缓冲区,然后进行一次打印系统调用。(). 我不推荐你在问题中展示的那种笨重的推送/弹出2循环方法,但它很流行而且确实有效。无论如何,
mov ax,cx
会将总和放入ax

您甚至可以通过使用一个10除1推的循环来获得一些代码重用,就像您在中所做的那样。第一次,用它来获得你弹出的数字,然后平方->求和。第二次,使用它生成总和的数字,然后弹出并打印。(但是编写一个在堆栈上留下可变数量内容的函数是一件棘手的事情;您可以在函数的开头弹出返回地址,然后按下/返回。或者只是将其设置为一个使用两次的宏,以便将两个位置都内联。)


如果您想与8086兼容,但要针对更新的Intel CPU进行调整(其中,因此成本与3 mov指令大致相同):您可以使用
mov-si,ax
/
mov-ax,dx
,然后是mul/add,然后是
mov-ax,si
,而不是
xchg-ax,dx
。对于实际的远古8086,
xchg
非常棒:更小的指令速度更快(除了像mul和div这样非常慢的指令),而
xchg
-与ax相比只有1个字节

当然,如果你真的关心速度,你会用它除以10。对于实际的8086,其中
mul
非常慢(但没有
div
慢),您可以使用正方形查找表在该部分保存mul:

    ; 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上的盈亏平衡,预取差异除外):


重复除以10一次只提取数字1(与dx中的余数相同),最不重要的第一位。加法是关联的,所以这很好;推送和分离的弹出循环部分是不必要的。为它制作一个函数似乎过于复杂了。特别是如果你有一个386兼容的,
imul-dx,dx
是很容易的,但是即使没有它,一对
mov
指令和一个备用寄存器(或者它周围的
xchg-ax,dx
)也能让你
mulal
(在不接触dx的情况下产生ax)/
添加cx,ax
。为什么要在内存中保留
[sum]
?x86有足够的寄存器用于此操作。您甚至可以使用
mov-si,dx
/
shl-si,1
/
add cx、[table+bx]
为正方形查找表编制索引,这在真正的8086上会更快。@PeterCordes的确,为每个基本任务创建单独的函数是无效的,但它有利于理解和调试。对于asm的初学者来说,在他们的第一堂课中不应该被优化策略所困扰。优化是写作/思考asm并发布答案的有趣之处。考虑优化甚至有助于理解编译器为何以这种方式生成代码。此外,更少的指令通常更容易理解——一些优化将代码简化为有趣的部分,去除了噪音。(然而,与其他观点不同,查表的想法不属于这一类。我只是想把这个想法写在某个地方。我想我应该把它放在我的答案中,因为我决定写一个。)我觉得很尴尬,但是你能写一个完整的程序来输出这个数量吗?因为我的老师给了我在DOs中输出数字的代码,而没有解释它是如何工作的,我对如何将我的代码与您的代码结合起来感到困惑solutions@Dsyder:不,谢谢,我对帮你做完整的家庭作业不感兴趣。此外,在AX中输入一个数字后,您实际上已经有了可以输出数字的代码。如果你想理解重复除以10的事情,请仔细阅读我的答案和/或思考会发生什么。还详细介绍了数学知识。非常感谢,我能够将你的答案和我的代码结合起来,结果很好!不幸的是,我无法推翻你的答案:(但我非常感谢你
    mov si, dx
    add cl, [table + si]
    adc ch, 0              ; carry to the high half of CX