Warm tip: This article is reproduced from serverfault.com, please click

assembly-打印整数的平方和(TASM)

(assembly - Print sum of squared digits of an integer (TASM))

发布于 2020-11-30 18:18:22

我正在尝试解决一个简单的组装任务(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   
Questioner
Dsyder
Viewed
11
Peter Cordes 2020-12-01 20:13:41

通过该打印循环,你已经一次获得一位数字。加法是关联的,因此无论你按什么顺序来添加它们,都可以从最低有效数字开始添加。

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(xchg3 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