实验七
题目
Power idea公司从1975年成立一直到1995年的基本情况如下。
年份 | 收入(千美元) | 雇员(人) | 人均收入(千美元) |
---|---|---|---|
1975 | 16 | 3 | ? |
1976 | 22 | 3 | ? |
1977 | 382 | 3 | ? |
1978 | 1356 | 3 | ? |
1979 | 2390 | 3 | ? |
1980 | 8000 | 3 | ? |
┇ | |||
1995 | 5937000 | 17800 | ? |
下面的程序中,已经定义好了这些数据: |
assume cs:codesg
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
;以上是表示21年的21个字符串
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;以上是表示21年公司总收入的21个dword型数据
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;以上是表示21年公司雇员人数的21个word型数据
data ends
table segment
db 21 dup('year summ ne ?? ')
table ends
end start
编程,将data段中的数据按如下格式写入到table段中,并计算21年中的人均收入(取整),结果也按照下面的格式保存在table段中。
思路
先确定一下数据的存放地址。
data段:
年份的数据占了21*4=84=54H。" db ‘1975’ “相当于"db 31H 39H 37H 35H”,“1”、“9”、“7”、"5"的ASCII码分别为31H 39H 37H 35H。
收入的数据占了21*4=84=54H。dword(双字节)型数据占4个字节32位。
雇员的数据占了21*2=42=2AH。word型数据占2个字节16位
由此可知,年份是0H~53H,收入是54H~A7H,雇员是A8H~D1H。
且有以下关系:
- data段地址+84(年份所占字节)=收入的数据起始地址
- data段地址+168(年份所占自己+收入所占字节)=雇员的数据起始地址
data段的数据占了DFH个字符,所以table段从E0H开始
如下图所示:
最暴力的方法就是4个循环21次分别把年份,收入,雇员数,人均收入存入table段中,刚开始想着能不能只循环一个21次就把所有数据插入table段中,结果发现似乎不太行。但是可以把年份和收入放在同一个循环中,然后雇员放在一个循环,平均收入放在一个循环,三个循环就解决了。
注意到年份和收入都是四字节,也就是他们可以同时使用一个增量di。由题目给的图可以知道数据要放在table段中的哪些位置。
程序如下:
assume cs:codesg
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
;以上是表示21年的21个字符串
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;以上是表示21年公司总收入的21个dword型数据
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;以上是表示21年公司雇员人数的21个word型数据
data ends
table segment
db 21 dup('year summ ne ?? ')
table ends
codesg segment
start:
mov ax,data
mov ds,ax
mov ax,table
mov es,ax
sub bx,bx
sub di,di
mov cx,21
dateIncome:
mov ax,ds:[di] ;年的前2个字节
mov es:[bx],ax
mov ax,ds:[di+84] ;收入的前2个字节
mov es:[bx+5],ax
add di,2
mov ax,ds:[di] ;年的后2个字节
mov es:[bx+2],ax
mov ax,ds:[di+84] ;收入的后两个字节
mov es:[bx+7],ax
add di,2
add bx,16
loop dateIncome
mov cx,21
sub bx,bx
sub di,di
g: ;雇员
mov ax,ds:[di+168]
mov es:[bx+10],ax
add di,2
add bx,16
loop gAve
mov cx,21
sub bx,bx
sub di,di
sub si,si
ave:
mov ax,ds:[di+84] ;收入低16位
mov dx,ds:[di+84+2] ;收入高16位
div word ptr ds:[si+168] ;雇员数
mov es:[bx+13],ax ;商放ax
add di,4
add si,2
add bx,16
loop ave
mov ax,4c00H
int 21H
codesg ends
end start
运行结果如下
改进
可以发现雇员和收入都是两个字节,考虑一下两者是否可以结合。整体上来看即从三个21次循环改为二个21次循环。
如下图所示,相同颜色的都可以整合:
整合如下:
程序如下:
assume cs:codesg
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
;以上是表示21年的21个字符串
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;以上是表示21年公司总收入的21个dword型数据
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;以上是表示21年公司雇员人数的21个word型数据
data ends
table segment
db 21 dup('year summ ne ?? ')
table ends
codesg segment
start:
mov ax,data
mov ds,ax
mov ax,table
mov es,ax
sub bx,bx
sub di,di
mov cx,21
dateIncome: ;处理年份和收入
mov ax,ds:[di] ;年份的前2个字节
mov es:[bx],ax
mov ax,ds:[di+84] ;收入的前2个字节
mov es:[bx+5],ax
add di,2
mov ax,ds:[di] ;年份的后2个字节
mov es:[bx+2],ax
mov ax,ds:[di+84] ;收入的后两个字节
mov es:[bx+7],ax
add di,2
add bx,16
loop dateIncome
mov cx,21
sub bx,bx
sub di,di
sub si,si
gAve: ;处理雇员和平均收入
mov dx,ds:[si+168] ;雇员的全部字节
mov es:[bx+10],dx
mov ax,ds:[di+84] ;收入的前两个字节
mov dx,ds:[di+84+2] ;收入的后两个字节
div word ptr ds:[si+168]
mov es:[bx+13],ax
add di,4
add si,2
add bx,16
loop gAve
mov ax,4c00H
int 21H
codesg ends
end start
再改进
上面的改进已经把三个21次循环改为两个21次循环。在观察一下看看能不能把程序改进为在一个21次循环里就把所有数据插入table段中。
如下图所示:
改进成:
发现还可以在改进,即直接用[bx+2]来获取年份的后两个字节,[di+84+2]来获取收入的后两个字节。
如下所示:
改进后的代码更加容易阅读。
完整代码如下:
完整版
assume cs:codesg
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
;以上是表示21年的21个字符串
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;以上是表示21年公司总收入的21个dword型数据
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;以上是表示21年公司雇员人数的21个word型数据
data ends
table segment
db 21 dup('year summ ne ?? ')
table ends
codesg segment
start:
mov ax,data
mov ds,ax
mov ax,table
mov es,ax
sub bx,bx
sub di,di
sub si,si
mov cx,21
all:
;年份存入table段
mov dx,ds:[di] ;年份的前2个字节
mov es:[bx],dx
mov dx,ds:[di+2] ;年份的后2个字节
mov es:[bx+2],dx
;收入存入table段
mov ax,ds:[di+84] ;收入的前2个字节 ;将收入的前两个字节放入ax
mov es:[bx+5],ax
mov dx,ds:[di+84+2] ;收入的后两个字节 ;将收入的后两个字节放入dx
mov es:[bx+7],dx
;雇员数存入table段
mov bp,ds:[si+168] ;雇员的全部字节
mov es:[bx+10],bp
;人均收入存入table段
div bp ;计算平均收入
mov es:[bx+13],ax
add di,4
add si,2
add bx,16
loop all
mov ax,4c00H
int 21H
codesg ends
end start
运行结果: