# 实验七

实验七

题目

Power idea公司从1975年成立一直到1995年的基本情况如下:

年份 收入(千美元) 雇员(人) 人均收入(千美元)
1975 16 3
1976 22 7
1977 382 9
1978 1356 13
1979 2390 28
1980 8000 38
~~~
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段中。

在这里插入图片描述

思路

碰到数据处理题,首先要弄清楚数据存放在哪里,大小是多少。

本题已知的数据类共三个,分别是年份,收入,雇员数。

  • 年份:

    共4个字节,从0B到3B,需要二重循环解决

  • 收入

    共4个字节,从5B到8B,需要二重循环解决

  • 雇员数

    共2个字节,从AB到BB,一个循环即可解决

table段地址怎么知道?

要想知道table段地址,首先要知道data段的长度,共21条记录,年份4个字节,收入4个字节,雇员数2个字节,共21*(4+4+2)=210个字节,16进制为00d2h,前文学过,段空间的基本单位为16字节一小节,不满补16字节,故虽然段空间大小为00d2h,但实际上为其分配了00e0h。

下面结合代码分析:

assume cs:codesg,ss:stacksg

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	

stacksg segment
    dw 10 dup(0); 定义一段栈空间,存放二重循环的cx和需要暂时更改的bx
stacksg ends

codesg segment
start:
    mov ax,data
    mov ds,ax
    mov ax,stacksg
    mov ss,ax
	mov bx,00e0h; 定义table段地址,不需要定义data段,因为可以直接加ds得到想要的数据,其实可以用es存
	
	push bx; 下面要对bx做法,故需存入栈中保存table段地址
	mov cx,21
	mov si,0

	s1:
	push cx
	mov cx,2; 按字循环,每次加两个字节
	mov di,0; di为目的段地址的偏移量,每次循环需要置零

	s11:
	mov ax,[si]; si为数据段地址,不断累加即可
	mov [bx+di],ax
	add si,2
	add di,2
	loop s11

	pop cx; 注意出入栈的顺序
	add bx,16; 通过加16,可以转到table下一行
	loop s1

	pop bx; 先出栈

	push bx; 再入栈
	mov cx,21
	mov si,0

	s2:
	push cx
	mov cx,2; 同s1循环,4个字节的传输
	mov di,0

	s21:
	mov ax,[84+si]; 因为年份数据共4*21=84
	mov [bx+5+di],ax; 位于table段的5B到8B
	add si,2
	add di,2
	loop s21

	pop cx
	add bx,16
	loop s2

	pop bx

	push bx
	mov cx,21
	mov si,0

	s3:
	mov ax,[168+si]; 在84基础上再加上4*21=168
	mov [bx+10],ax
	add si,2; 每次传一个字,不需要二重循环

	add bx,16
	loop s3

	pop bx

	mov cx,21
	
	s4:
	mov si,0
	mov ax,[bx+5+si]; 传低位
	mov dx,[bx+7+si]; 传高位
	div word ptr [bx+10]
	mov [bx+13],ax; 将商值传入对应内存单元
	add bx,16
	loop s4

	pop bx

	mov ax,4c00h
	int 21h

codesg ends
end start

本次实验遇到了几个问题:

  • 首先做本次实验,印象最深就是感觉寄存器不够用,不然一个循环就能搞定。但我写的这段代码也不够简洁,其实只要传输的数据大小一致就可以合并循环,因为可以共用一个偏移量,比如年份和收入都是4字节,就可以合并,同理雇员和人均收入都是两字节,也可以合并。
  • 其次,本次实验我也犯了一些错误:
    1. mov 内存单元,内存单元 这种语法是错误,必须经过寄存器中介
    2. 还有 xxx segment:这里冒号是错误的,经常debug后错误,很难发现
    3. 不存在[ax+bx],[di+si] 这种寻址方式
    4. 一开始找table段我只是加上21*(4+4+2)=210个字节,但实际上数据段是16个字节一个小节分配的,不满16补16的

优化版:

assume cs:codesg,ss:stacksg

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	

stacksg segment
    dw 10 dup(0)
stacksg ends

codesg segment
start:
    mov ax,data
    mov ds,ax
    mov ax,stacksg
    mov ss,ax
	mov bx,00e0h
	
	push bx
	mov cx,21
	mov si,0

	s1:
	push cx
	mov cx,2
	mov di,0

	s11:
	mov ax,[si]
	mov [bx+di],ax
	mov ax,[84+si]
	mov [bx+5+di],ax
	add si,2
	add di,2
	loop s11

	pop cx
	add bx,16
	loop s1

	pop bx

	; push bx
	; mov cx,21
	; mov si,0

	; s2:
	; push cx
	; mov cx,2
	; mov di,0

	; s21:
	; mov ax,[84+si]
	; mov [bx+5+di],ax
	; add si,2
	; add di,2
	; loop s21

	; pop cx
	; add bx,16
	; loop s2

	; pop bx

	push bx
	mov cx,21
	mov si,0

	s3:
	mov ax,[168+si]
	mov [bx+10],ax
	add si,2
	mov ax,[bx+5]
	mov dx,[bx+7]
	div word ptr [bx+10]
	mov [bx+13],ax
	

	add bx,16
	loop s3

	pop bx

	; mov cx,21
	
	; s4:
	; mov ax,[bx+5]
	; mov dx,[bx+7]
	; div word ptr [bx+10]
	; mov [bx+13],ax
	; add bx,16
	; loop s4

	; pop bx

	mov ax,4c00h
	int 21h

codesg ends
end start
posted @ 2023-07-12 11:33  三年、  阅读(79)  评论(0)    收藏  举报