运行结果(减少了部分数据量,不影响程序):
程序如下:
assume cs:code
;年份
year segment
db '1975','1978','1981','1984','1987','1990','1993','1995'
year ends
;收入
income segment
dd 16,1356,16000,97479,345980,1183000,3753000,5937000
income ends
;雇员
employee segment
dw 3,13,130,778,2258,5635,14430,17800
employee ends
table segment
;每列占9格,4列,8行
db 288 dup(' ')
table ends
code segment
start:
mov ax,table
mov es,ax
mov bx,0 ;定义年份的递增量
mov si,0 ;定义table的递增量
mov cx,8 ;循环添加8组数据到table中
loopyear:
;添加年份到table
mov ax,year
mov ds,ax
mov al,[bx]
mov es:[si],al
mov al,[bx+1]
mov es:[si+1],al
mov al,[bx+2]
mov es:[si+2],al
mov al,[bx+3]
mov es:[si+3],al
add bx,4 ;增加偏移量
add si,36
loop loopyear
mov bx,0 ;定义收入的递增量
mov si,0 ;定义table的递增量
mov cx,8 ;循环添加8组数据到table中
loopincome:
;转换收入为数字字符,添加到table中
push es
push si
mov ax,income
mov es,ax ;由于转换用到ds,所以我们用es来暂时表示income
mov ax,table
mov ds,ax
add si,9 ;从第9列开始保存收入
mov ax,es:[bx]
mov dx,es:[bx+2]
call ddtoc
pop si
pop es
add bx,4 ;增加偏移量
add si,36
loop loopincome
mov bx,0 ;定义收入的递增量
mov si,0 ;定义table的递增量
mov cx,8 ;循环添加8组数据到table中
loopemployee:
;转换雇员为十进制字符,添加到table中
push es
push si
mov ax,employee
mov es,ax
mov ax,table
mov ds,ax
add si,18
mov ax,es:[bx]
call dtoc
pop si
pop es
add bx,2 ;增加偏移量
add si,36
loop loopemployee
mov bx,0 ;定义收入的递增量
mov si,0 ;定义table的递增量
mov di,0 ;雇员递增量
mov cx,8 ;循环添加8组数据到table中
loopaverage:
;计算人均收入,并且转换为十进制字符,添加到tabl
push es
push si
mov ax,employee
mov es,ax
mov ax,income
mov ds,ax
mov ax,[bx]
mov dx,[bx+2]
div word ptr es:[di] ;商保存在ax中
mov dx,table
mov ds,dx
add si,27
call dtoc
pop si
pop es
;最后的空格保存为0表示这一行数据的结束,方便打印
mov ax,table
mov es,ax
mov dl,0
mov es:[si+35],dl
add bx,4 ;增加偏移量
add si,36
add di,2
loop loopaverage
mov dh,8 ;行号
mov dl,3 ;列号
mov cl,07h ;白色字
mov ax,table
mov ds,ax
mov si,0 ;循环加入字
mov bl,cl
mov cx,8
loopprint:
push bx
push cx
mov cl,bl
call show_str
pop cx
pop bx
;让dh加1
mov al,dh
mov ah,0
inc ax
mov dh,al
add si,36
loop loopprint
mov ax,4c00h
int 21h
;将word型数据转换为十进制字符串,ax是word型数据,ds:si指向字符串首地址
dtoc:
push ax
push di
push cx
push dx
push si
mov di,0 ;记录入栈多少次,就是有多少位数
s1:
mov cx,10d ;除10
mov dx,0
div cx
mov cx,ax ;如果商为0,那么求值完成
jcxz s2
add dx,30h
push dx ;把求得的ACSII入栈
inc di
jmp short s1
s2:
add dx,30h ;最后一次也要记录
push dx
inc di
mov cx,di
s3:
pop ax
mov [si],al ;ACSII码只占用了低8位
inc si
loop s3
pop si
pop dx
pop cx
pop di
pop ax
ret
;将dword型数据转换为十进制字符串,ax是dword型低16位,dx为高16位,ds:si指向字符串首地址
ddtoc:
push ax
push di
push cx
push dx
push si
mov di,0 ;记录入栈多少次,就是有多少位数
dds1:
mov cx,10d ;除10
call divdw
push cx
mov cx,ax ;如果商为0,那么求值完成
add cx,dx ;低和高相加一下,看看是不是为0
jcxz dds2
pop cx
add cx,30h
push cx ;把求得的ACSII入栈
inc di
jmp short dds1
dds2:
pop cx
add cx,30h ;最后一次也要记录
push cx
inc di
mov cx,di
dds3:
pop ax
mov [si],al ;ACSII码只占用了低8位
inc si
loop dds3
pop si
pop dx
pop cx
pop di
pop ax
ret
;解决除法溢出问题,ax保存低16位,dx高16位,cx为除数,
;结果低16位保存在ax,高16保存在dx,余数保存在cx
divdw:
push bx
push ax
mov ax,dx ;int(H/N)
mov dx,0
div cx
mov bx,ax ;商暂存到bx,乘65536是高16位
pop ax ;取出ax作为低16位,上次计算的余数在dx中,刚好做为高16位
div cx
mov cx,dx ;余数赋值给cx
mov dx,bx ;dx赋值为上次暂存的bx
pop bx
ret
;dh保存行号,dl保存列号,cl颜色,ds:si指向首地址
show_str:
push cx ;保存用到的寄存器
push si
push es
push di
push bx
push dx
mov ax,0b800h
mov es,ax
mov al,0a0h ;一行的总列数160字节
dec dh ;行号减1,因为是从0开始的
mul dh ;计算行开始偏移地址
mov bx,ax
mov al,2
mul dl ;计算列
sub ax,2 ;列也是从0开始,而且一个字符占两个字节
add bx,ax ;求出开始位置
mov di,0
mov al,cl
mov ch,0 ;高8位为0
s:
mov cl,ds:[si] ;判断是否到了字符结束
jcxz ok
mov es:[bx+di],cl
mov es:[bx+di+1],al
inc si
add di,2
jmp short s
ok:
pop dx
pop bx
pop di
pop es
pop si
pop cx
ret
code ends
end start