2015-04-17 42 views
4

該彙編代碼應該計算10個用戶輸入的4位數字的平均值,但我不知道爲什麼輸入的數字總是以2340作爲平均值。彙編中10個用戶輸入數字的平均值

data segment 
    sum dw 2dup(0) 
    msg1 db 'Enter 10 numbers:', 0dh,0ah,'$' 
    msg2 db 'Average= ','$' 
ends 

stack segment 
    dw 10dup(0) 
ends 

code segment 
    assume cs:code,ds:data,ss:stack 
    main proc far 

    mov ax, data 
    mov ds, ax 

    mov ax, stack 
    mov ss, ax 

    mov ah, 09h 
    mov dx, offset msg1 
    int 21h 

    mov ch, 10 

    NextNumber: 
    mov cl, 4 
    mov di, 0 

    get: 
    mov ah, 07h 
    int 21h 

    cmp al, 30h 
    jb get 
    cmp al, 39h 
    ja get 

    mov ah, 02h 
    mov dl, al 
    int 21h 

    sub al, 30h 

    mov bl, al 
    mov ax, 10 
    mul di 

    mov bh, 0 
    add ax, bx 

    mov di, ax 

    dec cl 

    jnz get 

    add sum, di 
    mov sum+2, 0 
    adc sum+2, 0 

    mov ah, 02h 
    mov dl, 0ah 
    int 21h 
    mov dl, 0dh 
    int 21h 

    dec ch 

    jnz NextNumber 

    mov dx, sum+2 
    mov ax, sum 
    mov bx, 10 
    div bx 

    mov ah, 09h 
    mov dx, offset msg2 
    int 21h 

    mov cx, 4 
    mov bx, 10 

    next1: mov dx, 0 
    div bx 

    push dx 

    dec cx 
    jnz next1 

    mov cx,4 

    next2: pop dx 
    add dl, 30h 
    mov ah, 02h 
    int 21h 

    dec cx 
    jnz next2 

    mov ah, 4ch 
    int 21h 

    main endp 

ends 

end main 
+2

如果您不能使用調試器來做到這一點,那麼您可以在方法中添加一些打印件以查看您的值變差的時間。輸入後打印'al'並在分割後打印,等等。對於這樣一個小程序,你應該能夠用幾個打印快速調試它。 –

+0

謝謝你,我調試它並發現問題。 – Asnira

回答

2
stack segment 
dw 10 dup (0) 
ends 

堆棧小隻是行不通......

mov ax, stack 
mov ss, ax 

...當然,除非你忘記設置SP寄存器因爲現在的程序可以認爲它有一個足夠大的堆棧。

add sum, di 
mov sum+2, 0 
adc sum+2, 0 

上面的代碼片段顯示了第一個問題。你不想連續地將變量的高位字清零。只需刪除mov sum+2, 0行。 總和變量位於數據段中,由編譯器初始化爲零。因此不需要運行時間從零開始。

mov dx, sum+2 
mov ax, sum 
mov bx, 10 
div bx 

mov ah, 09h 
mov dx, offset msg2 
int 21h 

而這段代碼顯示了第二個問題。您可以設法計算出平均值並將其存入AX寄存器,但是您可以通過調用DOS函數來顯示消息來銷燬AX寄存器!簡單地顛倒這些操作的順序。所以先顯示,然後計算平均值。

+0

真正的問題是AX被破壞,關於你提到的第一個問題,第一次我寫的代碼沒有「mov sum + 2,0」,我運行該程序,當平均值應該顯示我得到一個「Divide-Overflow」錯誤,所以我添加了「mov sum + 2,0」,沒有更多的錯誤。 – Asnira

+0

我明白了。你能告訴你爲什麼設置SS寄存器嗎?設置SS:SP尚未使用.EXE頭中的信息通過DOS完成? –

+0

我是Assembly的新成員,並且教會了我這些人,告訴我在每個代碼的開頭都寫下這些部分。 – Asnira

1

接下來是從鍵盤獲得10個數字並顯示平均值的程序。用EMU8086製造,並完全評論,以幫助您理解。希望它可以幫助你:

.stack 100h 
;------------------------------------------ 
.data 
;------------------------------------------ 
msj1 db 13,10,'Enter a number (4 digits): $' 
str db 6 ;MAX NUMBER OF CHARACTERS ALLOWED (5). 
     db ? ;LENGTH (NUMBER OF CHARACTERS ENTERED BY USER). 
     db 6 dup (?) ;CHARACTERS ENTERED BY USER. 
buf db 6 dup('$') ;WILL HOLD NUMBERS WITH 5 DIGITS OR LESS. 
suma dw 0 ;SUMATORY OF 10 NUMBERS. 
msj2 db 13,10,'Average : $' 
count db ? ;JUST A COUNTER. 
;------------------------------------------ 
.code   
;INITIALIZE DATA SEGMENT. 
    mov ax, @data 
    mov ds, ax 
;------------------------------------------   
;CAPTURE 10 NUMBERS 
    call clear_screen 
    mov count, 10 ;WE WILL CAPTURE 10 NUMBERS. 
ten_numbers: 
;DISPLAY MESSAGE. 
    mov ah, 9 
    mov dx, offset msj1 
    int 21h 
;CAPTURE NUMBER AS STRING. 
    mov ah, 0Ah 
    mov dx, offset str 
    int 21h 
;CONVERT CAPTURED NUMBER FROM STRING TO NUMERIC. 
    mov si, offset str ;PARAMETER FOR STRING2NUMBER. 
    call string2number ;NUMBER RETURNS IN BX. 
;ADD TO SUMATORY. 
    add suma, bx 
;REPEAT PROCESS FOR NEXT NUMBER. 
    dec count 
    jnz ten_numbers ;IF LAST OPERATION WAS NOT ZERO, JUMP 
;------------------------------------------ 
;AVERAGE. 
    mov ax, suma 
    mov bl, 10 
    div bl ;AX/BL = QUOTIENT:AL, REMAINDER=AH. 
;CONVERT QUOTIENT INTO STRING TO DISPLAY. 
    call dollars ;FILLS BUF WITH DOLLARS (REQUIRED TO DISPLAY). 
    mov ah, 0 ;CLEAR AH TO USE AX. 
    call number2string ;CONVERT AX. STRING RETURNS IN "BUF". 
;DISPLAY MESSAGE. 
    mov ah, 9 
    mov dx, offset msj2 
    int 21h 
;DISPLAY AVERAGE. 
    mov ah, 9 
    mov dx, offset buf 
    int 21h 
;------------------------------------------ 
;WAIT FOR ANY KEY. 
    mov ah,7 
    int 21h 
;------------------------------------------ 
;FINISH THE PROGRAM. 
    mov ax, 4c00h 
    int 21h   

;------------------------------------------ 
;NUMBER TO CONVERT MUST ENTER IN AX. 
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE 
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE 
;ORDER TO CONSTRUCT STRING (BUF). 
proc number2string 
    mov bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10. 
    mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS. 
cycle1:  
    mov dx, 0 ;NECESSARY TO DIVIDE BY BX. 
    div bx ;DX:AX/10 = AX:QUOTIENT DX:REMAINDER. 
    push dx ;PRESERVE DIGIT EXTRACTED FOR LATER. 
    inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED. 
    cmp ax, 0 ;IF NUMBER IS 
    jne cycle1 ;NOT ZERO, LOOP. 
;NOW RETRIEVE PUSHED DIGITS. 
    mov si, offset buf 
cycle2: 
    pop dx   
    add dl, 48 ;CONVERT DIGIT TO CHARACTER. 
    mov [ si ], dl 
    inc si 
    loop cycle2 

    ret 
endp 
;------------------------------------------ 
;CONVERT STRING TO NUMBER IN BX. 
;SI MUST ENTER POINTING TO THE STRING. 
proc string2number 
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT. 
    inc si ;POINTS TO THE NUMBER OF CHARACTERS ENTERED. 
    mov cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.           
    mov ch, 0 ;CLEAR CH, NOW CX==CL. 
    add si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT. 
;CONVERT STRING. 
    mov bx, 0 
    mov bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT. 
repeat: 
;CONVERT CHARACTER.      
    mov al, [ si ] ;CHARACTER TO PROCESS. 
    sub al, 48 ;CONVERT ASCII CHARACTER TO DIGIT. 
    mov ah, 0 ;CLEAR AH, NOW AX==AL. 
    mul bp ;AX*BP = DX:AX. 
    add bx,ax ;ADD RESULT TO BX. 
;INCREASE MULTIPLE OF 10 (1, 10, 100...). 
    mov ax, bp 
    mov bp, 10 
    mul bp ;AX*10 = DX:AX. 
    mov bp, ax ;NEW MULTIPLE OF 10. 
;CHECK IF WE HAVE FINISHED. 
    dec si ;NEXT DIGIT TO PROCESS. 
    loop repeat ;COUNTER CX-1, IF NOT ZERO, REPEAT. 

    ret 
endp  
;------------------------------------------ 
;FILLS VARIABLE BUF WITH '$'. 
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE 
;THESE STRINGS WILL BE DISPLAYED. 
proc dollars     
    mov si, offset buf 
    mov cx, 6 
six_dollars:  
    mov bl, '$' 
    mov [ si ], bl 
    inc si 
    loop six_dollars 

    ret 
endp 
;------------------------------------------ 
proc clear_screen 
    mov ah,0 
    mov al,3 
    int 10H 
    ret 
endp 

的過程string2numbernumber2string會在你未來的計劃是對你非常有用。注意它們的工作方式:string2number以0AH捕獲一個字符串並將其返回到BX,number2string從AX獲取數字並將其返回到名爲「buff」的變量(用'$'填充)。

如果您有任何問題,只需詢問。

相關問題