1. 程式人生 > >彙編實現15位加法(帶輸入和輸出)

彙編實現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。考慮到這個東西花了不少的時間了,就留待以後再改吧。