汇编题2-5
使用8086指令编写一个比赛得分程序。共有7个评委,按百分制打分,计分原则是去掉一个最高分和一个最低分,求平均值。要求:
(1)评委的打分以十进制从键盘输入。
(2)成绩以十进制给出,并保留1位小数。
enterline macro ;换行回车模块
mov dl,13
mov ah,2
int 21h
mov dl,10
mov ah,2
int 21h
endm
DATAS SEGMENT
buf DB 10,?,10 dup(0) ;ASCTONUM用
num DW 10 dup(0)
err db 'Illegal input! Please Try Again$' ;ASCTONUM用
flag db 0 ;NUMTOASC用
DATAS ENDS
STACKS SEGMENT PARA STACK
DW 100H DUP(0)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
;————————————代码开始段——————————————
XOR DI,DI ;接收10个10-999的整数
BEGREC:
CALL ASCTONUM
MOV num[DI],SI
ADD DI,2
CMP DI,14 ;(2n,n为待排数字个数)
JB BEGREC ;接收完成
CALL ORDER ;排序
XOR AX,AX
MOV SI,2
MOV CX,5
BEGINADD:
ADD AX,num[SI]
add SI,2
LOOP BEGINADD ;此时AX保存去掉最高分最低分后的得分总和
mov bx,5
div bl
xor bx,bx
mov bl,ah
xor ah,ah
mov si,ax
call NUMTOASC ;输出整数部分
mov dl,'.'
mov ah,2
int 21h
mov al,bl
xor ah,ah
mov bx,10
mul bl
mov bx,5
div bl
xor ah,ah
mov si,ax
call NUMTOASC ;输出小数部分
;————————————代码结束段——————————————
MOV AH,4CH
INT 21H
;--------------------子程序部分---------------------
ASCTONUM PROC;ascii码转换为十进制数字并保存至SI(无传入参数为,传出参数为SI,使用内存单元buf、err,含输入限制:0-100整数)
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
BEGIN1:
lea dx,buf
mov ah,10
int 21h
enterline
;思路:从最低位不断向高位扫描,每位-30H后*权重(1/10/100)
mov cl,buf+1 ;cl记录输入数据个数
xor ch,ch
xor di,di
xor dx,dx
mov bx,1 ;BX为权重,储存当前位的数字(储存在AX中)应该乘的数(1/10/100)
lea si,buf+2 ;si为当前位置下标
add si,cx
dec si
cov:mov al,[si] ;确认当前位符合要求(0-9)
cmp al,'0'
jb error
cmp al,'9'
ja error
sub al,30h ;AL储存当前位的数字(非ASCII码)
xor ah,ah ;AX储存当前位的数字(非ASCII码)
mul bx ;AX乘该位的权重
cmp dx,0 ;有溢出,报错
jne error
add di,ax ;将结果储存到DI,有溢出则报错
jc error
mov ax,bx ;BX(权重)乘10
mov bx,10
mul bx
mov bx,ax
dec si ;SI指针移向高一位
loop cov ;CX--,循环,直至CX为0,所有数据处理完毕
mov SI,DI ;接收数字部分完成,数字保存在SI中
CMP SI,100 ;范围控制,当前范围为0-100
JA error
jmp stop
error:
lea dx,err
mov ah,9
int 21h
enterline
jmp BEGIN1
stop:
POP DI
POP DX
POP CX
POP BX
POP AX
RET
ASCTONUM ENDP
NUMTOASC PROC;将SI寄存器中的十进制数转换为ASCII码并输出(传入参数为SI,无传出参数,使用内存单元flag,无空格无回车)
PUSH AX
PUSH BX
PUSH CX
PUSH DX
mov ax, SI ;(有效数值为0~65535) ;准备阶段
mov flag,0 ;从高位向低位扫描,第一次遇到不为0的位时flag置为1
mov bx,10000 ;BX为权重(目前为最高位权重)
cov2: ;循环开始
xor dx,dx
div bx ;AX/BX,余数(低于当前位的内容)存入DX,商(当前位)存入AX
mov cx,dx ;余数(低于当前位的内容)存入CX
cmp flag,0
jne nor2
cmp ax,0
je cont2
nor2: ;当flag==0且AX!=0 或 flag!=0时执行nor2
mov dl,al ;将AL中数字转为ascii码输出同时将flag置1
add dl,30h
mov ah,2
int 21h
mov flag,1
cont2: ;仅当flag==0且AX==0时,跳过nor2,不输出当前AL中的数字
cmp bx,10
je outer2 ;如果bx==0(已扫描到十位仍没发现不是0的数),跳到outer2
xor dx,dx ;BX/10
mov ax,bx
mov bx,10
div bx
mov bx,ax
mov ax,cx ;将AX的值改为 CX中储存的余数
jmp cov2 ;循环结束
outer2: ;将cl中数字转为ascii码输出
mov dl,cl
add dl,30h
mov ah,2
int 21h
stop2:
POP DX
POP CX
POP BX
POP AX
RET
NUMTOASC ENDP
ORDER PROC;选择排序法
PUSH DI
PUSH SI
PUSH AX
PUSH BX
PUSH CX
PUSH DX
XOR SI,SI;SI记录搜索轮次,第一次从0~18,第二次从2~18(2n-2,n为待排数字个数)
XOR DI,DI;DI为每轮搜索动态下标
MOV BX,DI;BX为每轮搜索最小值下标
BEGINSEARCH:
MOV DX,num[BX]
CMP DX,num[DI]
JB SKIP
MOV BX,DI
SKIP:
ADD DI,2
CMP DI,14 ;(2n,n为待排数字个数)
JAE FINISHALOOP
JMP BEGINSEARCH
FINISHALOOP:
MOV DX,num[SI];AX,DX为临时变量,交换num[SI],num[BX]
MOV AX,num[BX]
MOV num[SI],AX
MOV num[BX],DX
ADD SI,2
CMP SI,12 ;(2n-2,n为待排数字个数)
MOV DI,SI
MOV BX,DI
JBE BEGINSEARCH
POP DX
POP CX
POP BX
POP AX
POP SI
POP DI
RET
ORDER ENDP
;--------------------子程序部分结束---------------------
CODES ENDS
END START