彙編實現15位加法(帶輸入和輸出)
阿新 • • 發佈:2018-12-01
最近兩天一直在想可不可以用匯編做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。考慮到這個東西花了不少的時間了,就留待以後再改吧。