2017-05-21 41 views
0

這是我現在的代碼,但它只能做1位數字。這是班級,我不知道如何使它做多個數字。我仍然是ASM編程的初學者,我想請教如何做多位數字。如何在ASM中使用多位數字進行數學運算

.model small 
.stack 4096h 
.data 
msg1 db 'Choose an operation:$' 
msg2 db 'a. Addition$' 
msg3 db 'b. Subtraction$' 
msg4 db 'c. Multiplication$' 
msg5 db 'd. Division$' 
msg6 db 'You choose Addition.$' 
msg7 db 'You choose Subtraction.$' 
msg8 db 'You choose Multiplication.$' 
msg9 db 'You choose Division.$' 
msg11 db 'First number:$' 
msg12 db 'Second number:$' 
msg13 db 'Operation:$' 
msg14 db 'Answer:$' 
msg15 db 'Enter two numbers then choose the operation.$' 
op1 db ? 
op2 db ? 
res1 db ? 
res2 db ? 

.code 
start: 
mov ax,@data 
mov ds,ax 

_start: 
mov ah, 09h 
lea dx, msg15 
int 21h 
call newline 
mov ah, 09h 
lea dx, msg11 
int 21h 
mov ah, 01h 
int 21h 
sub al,30h 
mov op1, al 
call newline 
mov ah, 09h 
lea dx, msg12 
int 21h 
mov ah, 01h 
int 21h 
sub al,30h 
mov op2, al 
call newline 
mov ah, 09h 
lea dx, msg1 
int 21h 
call newline 
mov ah, 09h 
lea dx, msg2 
int 21h 
call newline 
mov ah, 09h 
lea dx, msg3 
int 21h 
call newline 
mov ah, 09h 
lea dx, msg4 
int 21h 
call newline 
mov ah, 09h 
lea dx, msg5 
int 21h 
call newline 
mov ah, 09h 
lea dx, msg13 
int 21h 
mov ah, 01h 
nt 21h 
cmp al, 'a' 
je _add 
cmp al, 'b' 
je _sub 
cmp al, 'c' 
je _mul 
cmp al, 'd' 
je _div 

_add: 
call newline 
lea dx, msg6 
mov ah, 09h 
int 21h 
call newline 
mov ax, 0 
mov al, op1 
add al, op2 
cmp al,0ah 
jge _twodig 
mov res2,al 
jmp _ans 

_sub: 
call newline 
lea dx, msg7 
mov ah, 09h 
int 21h 
call newline 
mov ax, 0 
mov al, op1 
sub al, op2 
mov res2,al 
mov res1,ah 
jmp _ans 

_mul: 
call newline 
lea dx, msg8 
mov ah, 09h 
int 21h 
call newline 
mov ax,0 
mov bx,0 
mov al, op1 
mov bl, op2 
mul bx 
mov res2,al 
jmp _mans 

_div: 
call newline 
lea dx, msg9 
mov ah, 09h 
int 21h 
call newline 
mov ax,0 
mov bx,0 
Mov dx,0 
mov al, op1 
mov bl, op2 
div bx 
mov res1, dl 
mov res2, al 
jmp _dans 

_twodig: 
sub al, 0ah 
mov ah,01h 
add ax, 3030h 
mov bx, ax 
lea dx, msg14 
mov ah, 09h 
int 21h 
mov dl,bh 
mov ah, 02h 
int 21h 
mov dl,bl 
mov ah, 02h 
int 21h 
jmp _loop 

_ans: 
lea dx, msg14 
mov ah, 09h 
int 21h 
mov al, res2 
add al, 30h 
mov dl,al 
mov ah, 02h 
int 21h 
jmp _loop 

_mans: 
mov dx, 0 
mov bl,0ah 
div bx 
mov ah,dl 
add ax, 3030h 
mov bx,ax 
cmp bl,30h 
je _ans 
lea dx, msg14 
mov ah, 09h 
mov dl,bl 
mov ah, 02h 
int 21h 
mov dl,bh 
mov ah, 02h 
int 21h 
jmp _loop 

_dans: 
lea dx, msg14 
mov ah, 09h 
int 21h 
mov al, res2 
mov ah, res1 
add ax, 3030h 
mov bx, ax 
mov dl,bl 
mov ah, 02h 
int 21h 
mov dl,'r' 
mov ah, 02h 
int 21h 
mov dl,bh 
mov ah, 02h 
int 21h 
jmp _loop 

_loop: 
mov ah,4ch 
int 21h 
newline proc 
mov dl, 0ah 
mov ah, 02h 
int 21h 
mov dl, 0d 
mov ah, 02h 
int 21h 
ret 
newline endp 

end start 
+1

我不明白你爲什麼作出這個如此複雜。從控制檯輸入讀取一個數字,將其存儲在一個寄存器中,從控制檯輸入中讀取另一個數字,將其存儲在第二個寄存器中,然後將這些寄存器的「ADD」(或「SUB」或「MUL」或「DIV」) 。這將爲您提供對8位,16位,32位或64位值的支持,具體取決於您使用的寄存器的大小。也許問題在於,你只能從控制檯輸入中每次只讀1個字符?考慮使用緩衝輸入或其他方式讓用戶表明他們已經完成了輸入。 –

+1

@CodyGray改變代碼以使用[緩衝的輸入(http://spike.scu.edu.au/~barry/interrupts.html#ah0a)可能不是一個很大的挑戰。但看着他的代碼,他似乎沒有真正的「atoi」功能,只是在做'sub al,30h'。將緩衝的字符串「1234」轉換爲寄存器的步驟對於新手來說可能是不明顯的。 Horlic,是否有助於將「1234」看作4 +(3 * 10)+(2 * 100)+(1 * 1000)?是的,這將是一個痛苦的寫作,但我不相信你會找到任何工具,無論是ASM或DOS會爲你做到這一點。讓你真正體會到C的庫,呃? –

回答

0

如果您意識到計算機如何使用數字,它可能會有所幫助。

與人類不同,它們不能應付在思想上抽象實體,而這數字是什麼。計算機需要一些物理表示,以對其進行操作和處理。

但人類做類似的事情,如果我想告訴你一些關於數字1234,我會寫這樣的「1234」,紙/屏幕上四種字體字形。這不再是真正的數字,而是基於10格式的「鏡像」,遠非完美。你怎麼讀回來並轉換成1234值?你明白每個數字都是十的不同的權力,你知道如何與這些工作。

對於計算機相同的原理被使用,但是它們的天然底爲2,數字0/1可以容易地編碼爲在電導線/細胞電流/無電流,所以這樣的單個0/1位被稱爲「位」。由於單個位只能存儲兩個值,因此我們傾向於將它們組合在一起,形成一個字節。現在一個字節(8位)可以存儲不同的值,當解釋爲無符號整數時將覆蓋範圍0..255。 16個比特可以覆蓋從065535值(或不同的,當你解釋的16個比特不同的值,例如與解釋爲符號值可以從-32768..+32767覆蓋整數值最上面的位)。

注意的是,16位沒有任何信息,是什麼樣的,他們保存價值,以及應如何解釋。它們只是16個0/1值的組合,以及如何解釋它們(無符號,有符號,單獨的位標誌,甚至是低精度浮點數,或者只是屏幕上的顏色或聲音的頻率,...),這取決於[您的]代碼以某種方式解釋該值。

8086寄存器是16位的,所以當你要使用像ADD, SUB, MUL, DIV本地運算指令,你需要先進行編碼的值到8/16位。

從用戶輸入您通常單獨的ASCII字符。因此,當用戶輸入「數字」1234時,您經常會收到例如5個字節的值:49,50,51,52,13(最後13個是「輸入」鍵)。現在嘗試運行以下算法:

bx = 0, si = address to first input 
while ([si] != 13) { // until enter is detected 
    ax = 10 
    mul bx ; 32bit "dx:ax" = bx*10 
    bh = 0, bl = [si++] 
    bl -= '0' ; '0' = 48 
    bx = bx + ax 
} 

第一次循環後bx將爲1(49-48 + 0)。
第二次循環後,bx將爲12(50-48 + 1 * 10)。
第三循環bx將爲123(51-48 + 12 * 10)。
第四循環bx將是1234(52-48 + 123 * 10)。
然後,while條件將檢測enter,並跳過計算,在bx中,您的值爲1234,二進制編碼爲16位(即電量在單元格中:0000 0100 1101 0010)。

所以這是可能性之一,如何將單獨的數字字符轉換爲本地二進制值。

然後顯示結果,你將有逆變換分裂機二進制值轉換成數字十的特別權力,轉換到這ASCII字符,並將結果輸出到屏幕/文件/ etc。

所有的這通常是任何高級編程語言容易獲得,但很少在ASM(一些初學者友好的平臺提供這作爲OS調用的一部分,但DOS是不是其中之一)。這就是說,要創建自己的完整+正確的替代clib printfscanf是項目幾個星期,並且我甚至不談論效率。但只要你需要一些基本的整數轉換來學習和玩耍,它就可以在一天內完成。只要意識到什麼是什麼,並注意計算機內部各種類型的值是如何編碼的(以及它們中的多少)。然後,可以使用簡單的數學公式將一種表示轉換爲另一種表示。


順便說一句,有方法(公式),怎麼做,甚至有獨立的數字(即做計算用「串」)的所有運算。這甚至有時是實用的,一些「任意精度」庫使用類似的原理來計算不符合本地8/16/32/64/128比特值的值。因此,上面的答案應該更像是「解鎖器」,以便讓您知道,掌握了什麼,並且您可以進行任何想要的轉換/計算,瞭解什麼是內容以及CPU如何工作。這不是唯一可能的方式,如何處理價值觀。

相關問題