汇编实现15位加法(带输入和输出)

  最近两天一直在想可不可以用汇编做15位加法,带输入和输出的那种,经过调试,大致的思路如下。

  有一个输入函数input,它接受从键盘输入的字符,并转换为数字存入内存;有一个输出函数output,它将已经转换过的结果输出;有一个加法函数plus,它实现的功能是把输入的两个数相加,并处理为ASCII码字符。

  input、output以及main函数都相对简单,我认为难点主要是在plus函数这一块。

  我刚开始想用两个指针分别指向两个数据,然后通过移动指针将数据相加,后来我发现这个方法有点麻烦(主要是不确定两个数据的长度是否一样,然后是否有进位);后来想到了另外一种方法,浮点数相加需要对阶,这里的加法也可以将短的数向右移(是整个数据右移,不是指移位操作),然后前面用0来补位,然后就方便处理了。

  具体的代码如下:

extrn input:far,output:far,plus:far
public num1,num2,result

data segment
	num1 db 16 dup(0)				; 存放已经经过转化的十进制数据
	num2 db 16 dup(0)
	result db 17 dup(0ffh),'$'
	onceMore db 10,'Do you want to add your numbers once more(y/n): $'
data ends 

code segment
assume cs:code,ds:data
start:
	mov ax,data
	mov ds,ax
	;--------------------------------------------------------------------
mainProcess:
	; 可能多次输入,所以需要将num1、num2和result重新初始化
	mov si,0
initNum:
	mov byte ptr [si],0
	inc si
	cmp si,20h
	jne initNum

initResult:
	mov byte ptr [si],0ffh
	inc si
	cmp si,31h
	jne initResult

	mov dl,10				; 回车
	mov ah,02h
	int 21h
	lea si,num1
	call input				; inputd的入口参数是si  目的是将输入的字符串转换为数字并存入si指向的内存中去
	cmp bl,0
	je endJudge
	mov di,si				; 首先保存第一次si的值

	lea si,num2
	call input				; inputd的入口参数是si  目的是将输入的字符串转换为数字并存入si指向的内存中去
	cmp bl,0
	je endJudge
	
	call plus
	call output
	
	;--------------------------------------------------------------------
endJudge:
	lea dx,onceMore
	mov ah,09h
	int 21h
	mov ah,01h
	int 21h
	cmp al,'y'
	je mainProcess

	mov ax,4c00h
	int 21h
code ends
end start

public input

data segment
    inputError db 10,'Input data error!$'
    inputMsg db 'Please input your data: $'
data ends

code segment
assume cs:code,ds:data
input proc far
    mov ax,ds
    mov es,ax           ; 后面存数据的时候需要主程序的ds
    push ds             ; 保存主程序中的ds
    mov ax,data
    mov ds,ax

    lea dx,inputMsg
    mov ah,9h
    int 21h 
    mov bl,1            ; bl为input函数是否成功标识,假设输入成功
    mov cx,16
loopIn:
    mov ah,01h
    int 21h             ; 调用 01h 号系统功能,输出为AL
    cmp al,0dh          ; 将al与回车比较
    je endIn
    cmp al,'0'          ; 数据合法性检验
    jb errorEnd
    cmp al,'9'
    ja errorEnd
    ; 数据合法,经过与'0'的减法操作,存入si指向的内存中
    sub al,'0'
    mov byte ptr es:[si],al
    inc si
    loop loopIn 
errorEnd:
    mov bl,0
    lea dx,inputError
    mov ah,9h
    int 21h
endIn:
    pop ds
    ret
input endp
code ends
end

public plus
extrn result:byte,num1:byte,num2:byte

code segment
assume cs:code

movBigToX macro X,Y,Z
    local ZBIGGER,endMov
    mov X,0
    cmp Y,Z
    jle ZBIGGER
    add X,Y
    jmp endMov
ZBIGGER:
    add X,Z
endMov:
    endm

plus proc far
    ; di指向num1最尾部
    ; si指向num2最尾部
    ; 往result里面存数据时指针就跟si和di中较大者保持一致    
    sub si,10h
    dec di
    dec si     
    mov bl,0                    ; bl为进位,由于在计算机内部使用16进制,必须处理      
    dec bp
; make Num Right Align
    push si                     
    push di                     ; 事先保存si和di的值
    cmp si,di                   ; si和di相等  无需对齐数据
    je preMyPlus
    cmp si,di
    jl alignNum2
alignNum1:
    mov al,num1[di]
    mov num1[si],al
    dec si
    dec di
    cmp di,-1
    je fillZeroNum1
    jmp alignNum1

alignNum2:                      ; si < di
    mov al,num2[si]
    mov num2[di],al
    dec si
    dec di
    cmp si,-1
    je fillZeroNum2
    jmp alignNum2

fillZeroNum1:
    mov num1[si],0
    dec si
    cmp si,-1
    jne fillZeroNum1
    jmp preMyPlus
fillZeroNum2:
    mov num2[di],0
    dec di
    cmp di,-1
    jne fillZeroNum2

preMyPlus:
    pop di
    pop si
    movBigToX bp,si,di          ; si > di?(bp = si):(bp = di)
    mov si,bp
    mov di,bp
    inc bp
myPlus:
    ; ds:[bp+result] = num1[di]+num2[si],si/di为-1怎么办,可以考虑先将短的数据右移,然后用0补位,这样运算要稍微简单一些
    cmp si,-1
    je plusOver
    mov al,num1[di]
    add al,num2[si]
    add al,bl
    cmp al,10d
    jl noCarry
    mov bl,1
    sub al,10d
    jmp giveValue
noCarry:
    mov bl,0
giveValue:
    mov byte ptr ds:[bp+result],al
    dec si                      ; 调整指针
    dec di
    dec bp
    jmp myPlus

plusOver:
    mov al,0
    add al,bl
    mov byte ptr ds:[bp+result],al

; 将数字的结果转化为字符
    mov si,0
numToChar:
    cmp byte ptr result[si],0ffh
    je printResult
    add byte ptr result[si],'0'
    inc si
    jmp numToChar
printResult:
    mov byte ptr result[si],'$'
    ret
plus endp
code ends
end

public output
extrn result:byte

data segment
    resultMsg db 'the add result is: $'
data ends

code segment
assume cs:code,ds:data
output proc far
    mov ax,ds
    mov es,ax           ; 后面存数据的时候需要主程序的ds
    push ds             ; 保存主程序中的ds
    mov ax,data
    mov ds,ax
    
    lea dx,resultMsg
    mov ah,09h
    int 21h

    pop ds
    lea dx,result
    mov ah,09h
    int 21h

    ret
output endp
code ends
end

  这四个文件需要分别编译,链接时以main为主。

  最开始一直错一直错,后来发现我把汇编中的extrn写成了extern,还是不够细心啊……

  这个程序只能够运算15位的加法,而且如果最前面没有进位的话,会多显示出来一个0。考虑到这个东西花了不少的时间了,就留待以后再改吧。

点赞