有一年多没有在CSDN上发博文了。人的工作重心总是有转移的,庆幸一直在做着有意义的事。
今天的内容,是为汇编语言课程更新一个实验项目。
本方案修改自王爽编《汇编语言》第4版P172“实验7寻址方式在结构化数据访问中的应用”
【数据描述】
烟园科技公司从2004年成立一直到2023年的基本情况如下。
年份 | 总收入(万元) | 雇员(人) | 人均收入(万元) |
---|---|---|---|
2004 | 22 | 7 | ? |
2005 | 382 | 9 | ? |
2006 | 1356 | 13 | ? |
2007 | 2390 | 28 | ? |
2008 | 8000 | 38 | ? |
…… | |||
2023 | 5937000 | 17800 | ? |
下面的程序中,已经定义好了这些数据:
assume cs:codesg
data segment
db '2004','2005','2006','2007','2008','2009','2010','2011','2012','2013'
db '2014','2015','2016','2017','2018','2019','2020','2021','2022','2023'
;以上是表示20年的20个字符串
dd 22,382,1356,2390,8000,16000,24486,50065,97479,140417
dd 197514,345980,590827,803530,1183000,1843000
dd 2759000,3753000,4649000,5937000
;以上是表示20年公司总收入的20个dword型数据
dw 7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;以上是表示20年公司雇员人数的20个word型数据
data ends
table segment
db 20 dup('year summ ne ??')
table ends`
【任务】
请编程序,将data段中的数据按如下格式整理到table段中,并计算20年中的人均收入(取整),记录到table段的相应位置上。
在table段中,一年的数据占16个字节,各字节分配如下表所示。
说明:与教材中提供的方案相比,每一部分的偏移地址为偶数,是更有效率的解决方案,而预留“保留”空间,既能让每一条记录所点空间保持16的倍数上(这是一个很好的特征),也为系统未来扩充等提供方便。
【提示】
①要做的工作主要是将data段中的数据复制到table段中,类似将数据做一个“扭转”;
②可将data段中的数据看成是多个数组,用DS指标该数据段,而将table中的数据看成是一个结构型数据的数组,每个结构型数据中包含多个数据项,用ES指示该数据段;
③寻址方式建议:可用bx定位每个结构型数据,用idata定位数据项,用si定位数组项中的每个元素,对于table中的数据的访问可采用[bx].idata和[bx].idata[si]的寻址方式;
④程序结构方面:可以将程序分为四块,分别用四个循环处理——复制年份、复制总收入、复制雇员数、计算人均收入,当然,这四个循环可以合并以提高效率。
【参考解答】
assume cs:codesg, ds:data
data segment
db '2004','2005','2006','2007','2008','2009','2010','2011','2012','2013'
db '2014','2015','2016','2017','2018','2019','2020','2021','2022','2023'
;以上是表示20年的20个字符串
dd 22,382,1356,2390,8000,16000,24486,50065,97479,140417
dd 197514,345980,590827,803530,1183000,1843000
dd 2759000,3753000,4649000,5937000
;以上是表示20年公司总收入的20个dword型数据
dw 7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;以上是表示20年公司雇员人数的20个word型数据
data ends
table segment
db 20 dup('YearSummNeAv????')
table ends
;定义代码段
codesg segment
start:
mov ax, data
mov ds, ax
mov ax, table
mov es, ax
;复制年份
mov cx, 20
mov si, 0 ;data段的数据项
mov bx, 0 ;table段年份的起始偏移地址
s1:
mov ax, [si] ;取data段中年份的前两字节
mov es:[bx], ax ;向table中复制年份的前两字节
mov ax,[si+2] ;取data段中年份的后两字节
mov es:[bx+2], ax ;向table中复制年份的后两字节
add si, 4 ;指向data段的下一个数据项
add bx, 16 ;指向table中下一年的位置
loop s1
;复制总收入
mov cx, 20
mov si, 0 ;data段的数据项
mov bx, 4 ;table段总收入的起始偏移地址
s2:
mov ax, [si+80] ;取data段中总收入的前两字节
mov es:[bx], ax ;向table中复制总收入的前两字节
mov ax,[si+82] ;取data段中总收入的后两字节
mov es:[bx+2], ax ;向table中复制总收入的后两字节
add si, 4 ;指向data段的下一个数据项
add bx, 16 ;指向table中下一年的位置
loop s2
;复制雇员人数
mov cx, 20
mov si, 0 ;data段的数据项
mov bx, 8 ;table段雇员人数的起始偏移地址
s3:
mov ax, [si+160] ;取data段中雇员人数
mov es:[bx], ax ;向table中复制雇员人数的前两字节
add si, 2 ;指向data段的下一个数据项
add bx, 16 ;指向table中下一年的位置
loop s3
;计算人均收入
mov cx, 20
mov bx, 0 ;table段雇起始偏移地址
s4:
mov ax, es:[bx+4] ;取总收入低16位
mov dx, es:[bx+6] ;取总收入高16位
div word ptr es:[bx+8] ;除以雇员数,完成除法,商存放在AX中
mov es:[bx+10], ax ;存储人均收入
add bx, 16 ;指向table中下一年的位置
loop s4
mov ax,4c00h
int 21h
codesg ends
end start
下面是程序运行后看到的一部分数据:
【进一步改进】
参考解答中使用了并行的4个循环。观察到循环中寻址方式一致,将循环适当合并,是可能且会获得效率上提升的。
用这个结构试着通思路,再改进出更高效率的解决方案,值得同学们一试。