装配中平均有10个用户输入的数字

时间:2015-04-17 17:58:28

标签: assembly average

这个汇编代码应该计算10个用户输入的4位数字的平均值,但我不知道为什么我输入的数字,它总是给我2340的平均值。

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 个答案:

答案 0 :(得分: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

上面的代码段显示了第一个问题。您不希望不断将 sum 变量的高位字归零。只需删除mov sum+2, 0行即可。 sum 变量位于数据段中,并由编译器初始化为零。因此,从零开始不需要运行时工作。

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

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

此代码段显示了第二个问题。您设法计算平均值并将其保存在AX寄存器中,然后通过调用DOS函数来销毁AX寄存器以显示消息!只需颠倒这些操作的顺序即可。首先显示,然后计算平均值。

答案 1 :(得分: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

程序 string2number number2string 对您未来的程序非常有用。注意它们的工作方式: string2number 采用0AH捕获的字符串并在BX中返回, number2string 从AX获取数字并将其返回到名为“buff”的变量中(填写'$')。

如果您有任何疑问,请询问。