第 9章 程序设计的一些编程技巧第 9章 程序设计的一些编程技巧
9.1 表处理程序设计
9.2 代码转换程序
9.3 算术运算
9.4 数值分析第 9章 程序设计的一些编程技巧
9.1 表处理程序设计
9.1.1 表的处理表的用途十分广泛:求平方值、立方值需要使用平方值表和立方值表,程序实现分支要用到跳转表等;大量供各种运算、查询等用的机器执行的任务,一组组的结果,一系列有关联的数据等等,都需要使用表来存储或处理。对表的处理通常包括查询、
插入、删除、排序和搜索等几个方面。将一新的内容插入到表中某个单元以前或以后,这里就需要先将插入位置以后的数据后移,
然后再将数据插入,同时表元素的个数也应做相应的修改 (增加 );
需要将表中某些内容删除时,为保持表的完整,应将被删内容以后的数据前移,并修改表元素个数;需要按某种规律 (升序或降序 )
将表中内容重新排列组织;需要在特定的表中查找给定某元素,
看是否存在此元素,存在何处,并做些其他处理等等。
第 9章 程序设计的一些编程技巧
9.1.2 表处理程序设计在表处理程序设计中,经常要用到 XLAT指令,XLAT指令称为查表转换指令,在 3.2.1节数据传送指令中已作过介绍。它是用表中的一个字节 (称为换码字节 )来置换累加器 AL中的内容,用此指令以前,要求先把表的起始地址送入 BX寄存器,且在 AL中置好所需的初值,AL中的初值为所需的换码字节在表中的相对位置 (用字节数给出 ),又可称为查找所需换码字节的索引值,然后
XLAT指令将 BX内容加上 AL内容所形成的地址单元中的内容 (即所需的换码字节 )放到 AL中去。
第 9章 程序设计的一些编程技巧
1,XLAT指令应用举例例 9-1 利用 XLAT指令把十六进制数转换成 ASCII码。
编程的基本思想是通过查表来实现进制的转换。
进制转换的方法有很多,这里介绍使用表的方法来实现转换。 XLAT指令是对表进行处理的,因此,要使用 XLAT指令,
就必须建立符合要求的表。程序中 HEXTAB是十六进制数表,
而 TAB_DA是 ASCII码表。
第 9章 程序设计的一些编程技巧
TABLE SEGMENT
TAB_DA DB 30H,31H,32H,33H
DB 34H,35H,36H,37H
DB 38H,39H,41H,42H
DB 42H,43H,44H,45H,46H
COUNT EQU $-TAB_DA
HEXTAB DB 0,1,2,3,4,5
DB 6,7,8,9,0AH
DB 0BH,0CH,0DH,0EH,0FH
第 9章 程序设计的一些编程技巧
ASIBUF DB 16 DUP(?)
TABLE ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
ASSUME CS∶ COSEG,DS∶ DATA
ASSUME ES∶ TABLE,SS∶ STACK
STR PROC FAR
第 9章 程序设计的一些编程技巧
START PUSH DS
MOV AX,0
PUSH AX
MOV AX,TABLE
MOV ES,AX
MOV DS,AX
MOV BX,OFFSET TAB_DA
MOV SI,OFFSET HEXTAB
MOV DI,OFFSET ASIBUF
MOV CX,COUNT
第 9章 程序设计的一些编程技巧
NEST,LODSB
XLAT TAB_DA
STOSB
LOOP NEST
RET
STR ENDP
COSEG ENDS
END START
第 9章 程序设计的一些编程技巧例 9-2 数据或程序的加密和解密。
为了使数据能够保密,可以建立一个密码表,利用 XLAT
指令将数据加密。程序接收键入的一个数字,如果是 0~ 9之间的一个数,加密后存入 MIMA单元。密码表可选择为原数字,0,1,2,3,4,5,6,7,8,9
密码数字,7,5,9,1,3,6,8,0,2,4
第 9章 程序设计的一些编程技巧加密程序描述如下:
DATA SEGMENT
MITAB DB '7591368024' ;加密密码表
CONT EQU $-MITAB
JMITAB DB '7384915062' ;解密密码表
MIMA DB?
DATA ENDS
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ DATA
STAR PROC FAR
PUSH DS
MOV AX,0
第 9章 程序设计的一些编程技巧
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV AH,1
INT 21H
AND AL,0FH
LEA BX,MITAB
XLAT MITAB
MOV MIMA,AL
RET
START ENDP
CODE ENDS
END STAR
第 9章 程序设计的一些编程技巧为了使程序能连续地接收键盘输入数字,可将程序设计成循环程序,遇到某一规定的标志字符时结束输入,并将输入的数字加密后存到内存缓冲区。在数据通信中也可以用类似的方法,先将要发送的代码加密以后再发送。为将加密后的数据或程序复原,可编写解密程序。下述程序段可将 MIMA
单元中的数据解密,结果送屏幕显示。
第 9章 程序设计的一些编程技巧
MOV AL,MIMA
AND AL,0FH
LEA BX,JMITAB
MOV AH,0
ADD BX,AX
MOV DL,[BX]
MOV AH,6
INT 21H
HLT
第 9章 程序设计的一些编程技巧还可以利用 XLAT指令将键盘输入的密码数字解密,下述程序接收键盘输入一个密码数字,解密后的数字在 AL中。
MOV AH,1
INT 21H
AND 0FH
LEA BX,JHITAB
XLAT JMITAB
HLT
第 9章 程序设计的一些编程技巧
2.查找、排序应用举例例 9-3 有一个 100个字节数据组成的数据表,其元素已按从小到大的顺序排列好了。现要求在此表上进行查找元素,具体的规则是:若表内有此元素,则结束;否则,按顺序将此元素插入表中的适当位置上并修改表长。
这是一个线性有序表的查找与插入的问题。我们已经知道,
线性表的插入操作是指在线性表的第 i-1个数据元素和第 i个数据元素之间插入一个新的数据元素,就是要使长度为 n的线性表
(ai,…,ai-1,ai,…,an)
变成长度为 n+1的线性表
(a1,…,ai-1,b,ai,…,an)
第 9章 程序设计的一些编程技巧数据元素 ai-1和 ai之间的逻辑关系发生了变化。由 100个字节数据组成的数据表若采用顺序存储结构,则逻辑上相邻的数据元素在物理位置上也是相邻的,因此,除非 i= n+1,否则必须移动元素才能反映这个逻辑关系的变化。
线性表的删除操作是指在第 i (1≤i≤n)个元素之前删除一个元素,这时需将第 i至第 n(共 n-i+1)个元素向后移动一个位置,即要使长度为 n的线性表
(a1,…a i-1,ai,ai+1,…,an)
变成长度为 n-1的线性表
(a1,…,ai-1,ai+1,...,an)
第 9章 程序设计的一些编程技巧数据元素 ai-1,ai和 ai+l之间的逻辑关系发生了变化,为了在存储结构上反映这个变化,同样需要移动元素。因此,本题设计的基本思想是:当发现表中无此元素时,应将其插在表中的适当位置上,即插在大于 (或等于 )前一个元素且小于 (或等于 )后一个元素的位置上,并将其后的元素依次后移。程序描述如下:
第 9章 程序设计的一些编程技巧
DATA SEGMENT
LTH DB 100 ;数据表长
TAB DB 5FH,… ;有序数据表
TEH DB 'X' ;设给定的元素是 X
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ DATA
ASSUME ES,DATA
STR PROC FAR
第 9章 程序设计的一些编程技巧
SYART,PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV BX,OFFSET TAB ; BX指向数据表
MOV AL,TEM ;取出给定的元素
MOV CX,LTH ;取出表长的值第 9章 程序设计的一些编程技巧
LOP,CMP AL,[BX] ;在表中进行查找
JE SOP ;若找到,则转 SOP
JL INST ;若给定元素小于表内元素,转 INST插入
INC BX
DEC CX
JNZ LOP
MOV [BX],AL ;给定元素始终大于 (或等于 )表内元素
JMP JUST ;应将给定元素插在表的末尾
INST,MOV AH,[BX] ;取出表中元素暂存于 AH
MOV [BX],AL ;插入给定的元素
INC BX
第 9章 程序设计的一些编程技巧
LOPI,MOV AL,[BX]
MOV [BX],AH ;表中插入位置后的元素后移
INC BX
MOV AH,[BX]
MOV [BX],AL
INC BX
DEC CX
DEC CX
JNZ LOPI
JUST,INC LTH ;修改表长
SOP,RET
STR ENDP
CODE ENDS
END START
第 9章 程序设计的一些编程技巧例 9-4 顺序查找法。
如果要查找的内容与表之间没有什么规律可循,则只好从表首开始逐个比较、查找,即采用顺序查找 (Sequential Search)
的方法。顺序查找的查找过程为:从表中第 n个记录开始,逐个进行记录的关键字和给定值的比较,若某个记录的关键字和给定值比较相等,则查找成功,找到所查记录;反之,若直至第一个记录,其关键字和给定值都不等,则表明表中没有所查记录,查找不成功。
第 9章 程序设计的一些编程技巧设一组数据存放在内存以 SSEG为首址的连续单元中,用
DB定义,可描述如下:
SSEG DB 40H,79H,24H,30H,33H,1AH,0EH
根据上述顺序查找的基本思想,可写出如下的程序:
SEQ_DATA SEGMENT
SSEG DB 40H,79H,24H,30H,33H,1AH,0EH,
6DH,87H,9BH ;定义数据表
XX DB? ;设定待查找的元素
SEQ_DATA ENDS
第 9章 程序设计的一些编程技巧
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
SEQ_CODE SEGMENT
ASSUME CS,SEQ_CODE,DS,SEQ_DATA
ASSUME ES,SEQ_DATA,SS:STACK
SEARCH PROC FAR
START,PUSH DS
MOV AX,0
PUSH AX
MOV AX,SEQ_DATA
MOV DS,AX
第 9章 程序设计的一些编程技巧
MOV ES,AX
MOV AL,XX ;设任给的数据元素在 XX单元中
MOV CX,10H ;取表长
MOV BX,OFFSET SSEG ; BX指向表的首地址
MOV AH,0
LOP1,CMP AL,[BX]
JE AT
INC AH
INC BX
L00P L0P1
MOV AL,0FFH ;若查找不到,0FFH送 AL
RET
第 9章 程序设计的一些编程技巧
AT,MOV AL,AH ;查找到时,AH中为对应的十六进制数
RET
SEARCH ENDP
SEQ_CODE ENDS
END START
第 9章 程序设计的一些编程技巧例 9-5 折半查找法。
折半查找 (Binary Search)的查找过程是:对一个有序表,先确定待查记录所在的范围 (区间 ),然后逐步缩小范围直到找到或找不到该记录为止。
如已知如下 11个数据元素的有序表:
(02,11,17,20,35,51,60,77,83,89,97)
现要查找关键字为 20和 85的数据元素。
假设指针 L和 H分别指示待查元素所在范围的下界和上界,
指针 M指示区间的中间位置,即 M = [(L+H)]/2。在此例中,L和 H
的初值分别为 1和 11,即 [1,11]为待查范围。
第 9章 程序设计的一些编程技巧查找给定值 K= 20的过程:
02 11 17 20 35 51 60 77 83 89 97
↑L ↑M ↑H
先令查找范围中间位置的数据元素的关键字 BUF[M]与给定值 K
相比较,因为 BUF[M] > K,说明待查元素若存在,必在区间 [L,
M-1]的范围内,则令指针 H指向第 M-1个元素,重新求得 M=
[(1+5)/2]= 3
02 11 17 20 35 51 60 77 83 89 97
↑L ↑M ↑H
第 9章 程序设计的一些编程技巧仍以 BUF[M]和 K相比,因为 BUF[M] < K,说明待查元素若存在,必在 [M+1,H]范围内,则令指针 L指向第 M+1个元素,
求得 M的新值为 4,比较 BUF[M]和 K,因为相等,则查找成功,
所查元素在表中序号等于指针 M的值。
02 11 17 20 35 51 60 77 83 89 97
↑L ↑H
↑M
第 9章 程序设计的一些编程技巧查找 K=85的过程:
02 11 17 20 35 51 60 77 83 89 97
↑L ↑M ↑H
BUF[M] < K,令 L = M + 1:
02 11 17 20 35 51 60 77 83 89 97
↑L ↑M ↑H
BUF[M] < K,令 L = M + 1:
02 11 17 20 35 51 60 77 83 89 97
↑L ↑H
↑M
第 9章 程序设计的一些编程技巧
BUF[M] > K,令 H= M -1:
02 11 17 20 35 51 60 77 83 89 97
↑H ↑L
此时,因为下界 L大于上界 H,则说明表中没有关键字等于 K的元素,查找不成功。从上述例子可见,折半查找过程是以处于区间中间位置记录的关键字和给定值比较,若相等,则查找成功,若不等,则缩小范围,直至新的区间中间位置记录的关键字等于给定值或者查找区间的大小小于零时 (表明查找不成功 )为止。
第 9章 程序设计的一些编程技巧
NAME BINARY_SEARCHIHG
BUF_DAT SEGHENT
BUFFER DB '$ AGHI NRSTUVWXYZ'
COUNT EQU $-BUFFER ;存放查找次数或未找到标记
PTRN DW? ;关键字 'A'
CHAR EQU 'A'
BUF_DAT ENDS
STACK SEGHENT PARA STACK 'STACK‘
STACK ENDS
第 9章 程序设计的一些编程技巧
CODE SEGMENT
ASSUME CS∶ CODE,DS∶ BUF_DAT
ASSUME ES∶ BUF_DAT
STR PROC FAR
START,PUSH DS
MOV AX,0
MOV AX,BUF_DAT
MOV DS,AX
MOV ES,AX
MOV SI,OFFSET BUFFER ;区间上限送 SI
第 9章 程序设计的一些编程技巧
MOV CX,COUNT
MOV DX,1 ;记录查找次数
MOV AX,SI
ADD AX,CX ;最后一个数的地址加 1
MOV DI,AX ;下限送 DI
MOV AL,CHAR
CONTL,MOV BX,SI
ADD BX,DI
SHR BX,1 ; BX中为 M
CMP AX,[BX] ;关键字与 BUF[M]比较
JZ FOUND ;找到转 FOUND
第 9章 程序设计的一些编程技巧
PUSHF ;保护标志
CMP BX,SI ; M=上限否
JZ NOFID ;相等未找到
POPF
JL LESS ;关键字 < BUF[M]
MOV SI,BX ; M作上限
JMP NEXT
LESS,MOV DI,BX ; M作下限
NEXT,INC DX ;查找次数加 1
JMP CONTL
第 9章 程序设计的一些编程技巧
NOFID,MOV DX,0FFFFH ;未找到标记设为 0FFFFH
FOUND,MOV AX,DX
MOV PTRN,AX ;结果送 PRTN单元
RET
STA ENDP
CODE ENDS
END START
第 9章 程序设计的一些编程技巧
9.2 代码转换程序对于许多应用实例来说,代码转换是必需的。例如,当从键盘上输入一个数字,机器中接收到的是它的 ASCII码值。为使这个数字能参与运算,必须先将其转换成二进制数或十进制数。如果内存中的二进制数要在屏幕上以十进制形式显示出来,则首先要将其转换成十进制数,再转换成 ASCII码才能够输出。常用的进制有:二进制、十进制、十六进制,BCD码,ASCII码等。本节主要讨论 ASCII码转换成 BCD码,BCD码转换成 ASCII码、二进制数转换为 ASCII码和 ASCII码转换成二进制数等问题。
第 9章 程序设计的一些编程技巧例 9-6 ASCII码转换成 BCD码。
在微机中,从键盘上输入的十进制数的每一位数码 (即 0~ 9中任一个 ),都是以它的 ASCII码表示的;要向 CRT输出的十进制数的每一位代码也是用 ASCII码表示的。而在机器中,一个十进制数,或者把它转换为相应的二进制数存放,或者是以 BCD码形式存放。若在内存的输入缓冲区中,已有若干个用 ASCII码表示的十进制数据,则每一个存储单元只存放一位十进制数码。要求把它转换为相应的 BCD码,且把两个相邻单元的十进制数码的 BCD
码合并在一个存储单元中,且地址高的放在前 4位,这样就可以节省一半的存储单元。十进制数的 ASCII码转换为 BCD码的方法是把高 4位变为 0;若是以组合方式存储转换后的 BCD码,则要把两位并在一个存储单元中,可将地址高的字节左移 4位,再与地址低的字节组合在一起。
第 9章 程序设计的一些编程技巧程序描述如下:
DATA SEGMENT
ASCBUF DB 31H,32H,33H,34H,35H,36H,37H,38H,39H,30H
COUNT EQU $-ASCBUF
BCDBUF DB 5 DUP(?)
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSED SEGMENT
ASSUME CS∶ COSEG,DS∶ DATA,ES∶ DATA,SS∶ STACK
第 9章 程序设计的一些编程技巧
STR PROC FAR
GO,PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV SI,OFFSET SACBUF
MOV DI,OFFSET BCDBUF
MOV CX,COUNT
ROR CX,1 ;右移最低位进 CF,若数据个数为偶数则转移第 9章 程序设计的一些编程技巧
JNC NEXT
ROL CX,1
LODSB ;取一数进 AL,指针 SI+1
AND AL,0FH ;转换成 BCD码
STOSB ;送入内存单元,DI+1
DEC CX ;数据个数减 1
ROR CX,1 ;数据个数除 2
NEXT,LODSB
AND,AL,0FH
MOV BL,AL ;转换一个 ASCII码到 BCD码
LODSB
PUSH CX ;保护 CL的内容第 9章 程序设计的一些编程技巧
MOV CL,4
SAL AL,CL ;再转换一个 ASCII码到 BCD码存入高四位
POP CX
ADD AL,BL ;两个 BCD码合为一个字节
STOSB
LOOP NEXT ; CX-1,CX≠0转 NEXT,重复,直到 CX= 0结束
RET
STR ENDP
COSE ENDS
END GO
第 9章 程序设计的一些编程技巧需要说明的是,输入缓冲区中,已存放的 ASCII码的个数可能是偶数,也可能是奇数。若是奇数,则先把地址最低的一个 ASCII码转换为 BCD码 (高四位为 0),然后把剩下的偶数个
ASCII码按统一的方法处理。程序中的指令 ROR CX,1的作用是用于判断已存放的 ASCII码的个数是否奇偶。具体方法是将
CX的最低位右移进 CF,若 CF=0,则为偶数,否则为奇数。
第 9章 程序设计的一些编程技巧例 9-7 BCD码转换成 ASCII码。
BCD码的十进制数在 CRT上显示时,首先应将其转换为
ASCII码。下述程序自动在 CRT上输出 0~ 98之间的十进制数。
由于是显示 0~ 98之间的数,因此,不论是哪一个数,其数字均在 0~ 9之间,而不会出现 A~ F的情况。 BCD码转换成 ASCII
码采用的是 BCD码 +30H的方法。
第 9章 程序设计的一些编程技巧
STACK SEGMENT PARA STACK 'STACK'
STP DB 100 DUP(?)
STACK ENDS
DATA SEGMENT;定义缓冲区
BUFR DB 3 DUP(?)
DATA ENDS
COSEG SEGMENT
ASSUME CS∶ COSEG,DS∶ DATA,ES∶ DATA
第 9章 程序设计的一些编程技巧
START,PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV BL,-1
PUSH BX ;保护 BL
第 9章 程序设计的一些编程技巧
GOON,MOV SI,OFFSET BUF
MOV DL,0DH ;输出回车
MOV AH,2
INT 21H
MOV DL,0AH ;输出换行
MOV AH,2
INT 21H
POP BX
MOV AL,BL ;产生 0~ 98之间的数据
INC AL
DAA
第 9章 程序设计的一些编程技巧
CMP AL,99H
JNC OVER ;若数字大于 98,结束程序
MOV BL,AL
PUSH BX ;保护 BL,以便下个循环在此数上加 1
MOV DL,AL ;暂存入 DL,以备转成 ASCII码用
MOV CL,4
SHR AL,CL ;右移四次
OR AL,30H ;高位十进数转成 ASCII码
MOV [SI],AL ;存到缓冲区
INC SI
MOV AL,DL ;恢复原十进制数第 9章 程序设计的一些编程技巧
AND AL,0FH
OR AL,30H ;低位十进制数转成 ASCII码
MOV [SI],AL
INC SI
MOV AL,'$'
MOV [SI],AL ; '$'存入缓冲区,9号调用要求的
MOV DX,OFFSET BUFR
MOV AH,9
INT 21H ;缓冲区数据输出显示
MOV CX,0FFFFH
第 9章 程序设计的一些编程技巧
AGN,DEC CX ;延时后再显下一个数
JNE AGN
JMP GOON
OVER:
COSEG ENDS
END START
第 9章 程序设计的一些编程技巧通过本例,有两点是值得我们学习的:
(1) 数据自动产生的方法。即使用一段循环程序,在进入循环程序之前,先将 -1送 BL寄存器,然后执行下述的循环:
MOV AL,BL
INC AL
DAA
CMP AL,99H
JC NEXT
MOV AL,0
第 9章 程序设计的一些编程技巧
(2) 延时程序的编制。该程序使用延时的目的是使数据在屏幕上有足够的显示时间。延时程序段描述如下:
MOV CX,0FFFFH
AGN,DEC CX
JNE AGN
第 9章 程序设计的一些编程技巧例 9-8 二进制数转换为 ASCII码。
设 CX寄存器中有一个带符号的二进制数,现将其以十进制形式输出到 CRT。 CX中的数是十六进制数,所表示的数的范围在 -32 768~ +32 767之间。程序应先检查 CX中数的符号位,
以决定输出“+”或“-”。若是负数,应先求补,得到原码,
然后再将其转换为十进制数。转换方法是先将其减 10000,看其中包含几个 10000,那么它的十进制数的万位数字就是包含的一万的个数,不够减时再用余下的数减 1000,统计其中包含
1000的个数,得到千位上的数字,依此类推,求出百位、十位的数字,剩下的就是个位数字了。转换后的十进制数在缓冲区的存放格式如图 9-1所示。有了十进制数字后,要在 CRT显示出来,还要将其转换成 ASCII码才能输出。程序描述时采用子程序的形式:
第 9章 程序设计的一些编程技巧图 9-1 内存缓冲区存放格式
‘ + ’ 或 ‘ - ’ 符号位万 位千 位百 位十 位个 位
RA M
第 9章 程序设计的一些编程技巧
DATA SEGMENT
COUNT DW?
BUF DB 9 DUP(?)
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
COSGE SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK
第 9章 程序设计的一些编程技巧
START PROC FAR
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV CX,COUNT ; CX中为待输出的二进制数
CALL PTDN
RET
第 9章 程序设计的一些编程技巧
START ENDP;输出 16位二进制带符号数的子程序;入口参数,CX中为待输出的数据;所用子程序,CHANG
PTDN PROC
PUSH AX
PUSH BX
PUSH DX
PUSH SI ;保护现场
MOV BX,OFFSET BUF ; BX指向缓冲区第 9章 程序设计的一些编程技巧
MOV AL,0DH
MOV [BX],AL ;回车符存入缓冲区以便显示时回车
INC BX
MOV AL,0AH
MOV [BX],AL ;换行符存入缓冲区
INC BX
MOV AL,CH
OR AL,AL ;查看符号位
JNS PLUS ;正数转 PLUS
第 9章 程序设计的一些编程技巧
NEG CX ;负数求补
MOV AL,'-'
MOV [BX],AL ;缓冲区存入负号
JMP GOON
PLUS,MOV AL,'+'
MOV [BX],AL ;缓冲区存入正号
GOON,INC BX
MOV SI,10000
CALL CHANG ;求万位数,并转换为 ASCII码存入缓冲区
MOV SI,1000
CALL CHANG ;求千位数
MOV SI,100
第 9章 程序设计的一些编程技巧
CALL CHANG ;求百位数
MOV SI,10
CALL CHANG ;求十位数
MOV AL,30H
ADD AL,CL
MOV [BX],AL ;求个位数
INC BX
MOV AL,'$' ; $送入缓冲区尾,9号功能调用所要求
MOV [BX],AL
MOV DX,OFFSET BUF
第 9章 程序设计的一些编程技巧
MOV AH,9 ; 9号功能调用输出显示
INT 21H
POP SI
POP DX
POP BX ;恢复现场
POP AX
RET
PTDN ENDP
第 9章 程序设计的一些编程技巧;本子程序统计 CX寄存器所包含权 (在 SI中 )的个数,并把这个个数转换成
ASCII码;入口参数,SI为权码,CX中为给定的数,BX指向 ASCII码结果缓冲区;出口参数:结果缓冲区的当前单元存放转换完的 ASCII码,并且调整 BX指向缓冲区的下; 一个单元
CHANG PROC
MOV DL,0 ; DL存放权的个数,初值 0
AGAIN,SUB CX,SI
JC DOWN ;不够减转 DOWN
INC DL ;够减 DL加 1
JMP AGAIN ;再减权第 9章 程序设计的一些编程技巧
DOWN,ADD CX,SI ;恢复 CX
MOV AL,30H
ADD AL,DL
MOV [BX],AL ;转 ASCII码并存入缓冲区
INC BX ;指针调整
RET
CHANG ENDP
CODE ENDS
END START
第 9章 程序设计的一些编程技巧例 9-9 ASCII码转换成二进制数。要求编制接收从键盘上输入的十进制整数的程序 (设数的范围为 -32 768到 +32 767)。
接收键盘输入可用 10号功能调用,10号功能调用要求预先定义一个缓冲区,缓冲区的第一单元存放缓冲区长度,第二单元留作存放实际输入的字符个数,第三单元开始存放数据,这可在数据段加以定义。
第 9章 程序设计的一些编程技巧从键盘接收的十进制数字的 ASCII码字符,应将它转换为二进制数,转换的方法是:先将其转换成十进制数字,再用累加和乘 10加 X的方法变成二进制数。如,将 369转换成二进制数,
可先将累加和赋为 0,再计算 (((0× 10+3)× 10+6)× 10+9),结果就是二进制数,然后再由符号位决定是否需要求补。
程序的编制采用子程序的结构,能实现从键盘上接收两个带符号十进制数,将它们转换成二进制数,并且求出这两个数的乘积,然后再将乘积的高、低位字节分别转换成十进制数在屏幕上显示出来的功能。
第 9章 程序设计的一些编程技巧
DATA SEGMENT
BUF DB 10
DB?
DB 10 DUP(?) ;定义输入缓冲区
SIGN DB? ;存放输入数据的正负标志
BLK DB 9 DUP(?) ;输出缓冲区
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
COSGE SEGMENT
ASSUME CS:COSEG,DS:DATA,ES:DATA,SS:STACK
第 9章 程序设计的一些编程技巧
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
CALL GETD ;接收键入的第一个带符号十进制数并转换成二进制数
PUSH CX
MOV DL,0DH
第 9章 程序设计的一些编程技巧
MOV AH,2
INT 21H
MOV DL,0AH
MOV AH,2
INT 21H ;输出回车换行
CALL GETD ;接收第二个十进制数,并转换成二进制数
POP AX
IMUL CX ;两个数相乘结果在 DX,AX
CALL PUTDN ;准备将二进制积转换为十进制,
先处理符号第 9章 程序设计的一些编程技巧
MOV CX,DX
CALL GOON ;积的高位字转换为十进制数输出
MOV CX,AX
CALL GOON ;积的低位字转换为十进制数输出
RET
START ENDP;输入十进制数,并将其转换成二进制数;结果在 CX中;所用寄存器,AX,BX,DX,SI
GETD PROC
第 9章 程序设计的一些编程技巧
PUSH AX
PUSH BX
PUSH CX
PUSH SI
MOV DL,','
MOV AH,2
INT 21H ;输出提示符“:”
MOV DX,OFFSET BUF
MOV AH,10
MOV 21H ;接收键盘输入
MOV SI,OFFSET BUF+1
MOV BL,[SI] ;实际输入的字符个数送 BL
DEC BL
第 9章 程序设计的一些编程技巧;记录符号位
INC SI
MOV AL,0
MOV SIGN,AL ;符号单元送 0
MOV AL,[SI] ;取实际符号位
CMP AL,'+'
JZ NEXT1 ;若实际符号位为负
MOV AL,1 ;则符号单元送 1
MOV SIGN,AL; ASCII码转换成 BCD码
NEXT1,PUSH BX ;保存字符个数第 9章 程序设计的一些编程技巧
NEXT2:INC SI
MOV AL,[SI]
AND AL,0FH
MOV [SI],AL ; ASCII码转换成 BCD码送回
DEC BL ;字符个数减 1
JNZ NEXT2 ;若不等于 0,继续转换
POP BX; BCD码转换成二进制码
MOV DI,OFFSET BUF+3
MOV CX,0 ;累加和置初值第 9章 程序设计的一些编程技巧
AG1,PUSH BX
ADD CX,CX
MOV BX,CX
ADD CX,CX
ADD CX,CX
ADD CX,BX ;累加和 *10
MOV BL,[DI]
MOV BH,0
INC DI
ADD CX,BX ;累加和乘 10后加下一个 BCD数字
POP BX
第 9章 程序设计的一些编程技巧
DEC BL
JNE AG1 ;未转换完时继续
MOV AL,SIGN
OR AL,AL ;查看符号位
JZ DONE
NEG CX ;若为负数求补
DONE,POP SI
POP DX
POP BX
POP AX
RET
第 9章 程序设计的一些编程技巧
GETD ENDP;本过程根据 DX和 AX中的一个带符号数的正负号在缓冲区建立符号标志,并输出;所用寄存器,BX,CX;入口参数,DX和 AX中为一带符号二进制数;出口参数,DX和 AX中的内容为原数的原码
PUTDN PROC
PUSH CX
PUSH BX
MOV BX,OFFSET BLK
MOV CL,0DH
第 9章 程序设计的一些编程技巧
MOV [BX],CL
INC BX
MOV CL,0AH
MOV [BX],CL ;回车、换行送输出缓冲区
INC BX
OR DH,DH
JNS PLUS
NOT AX
NOT DX
ADD AX,1
JNC AD1
INC DX ;负数求补第 9章 程序设计的一些编程技巧
AD1,MOV CL,'-'
MOV [BX],CL
JMP RON
PLUS,MOV CL,'+'
MOV [BX],CL
RON,INC BX
MOV CL,'$'
MOV [BX],CL
PUSH AX
MOV DX,OFFSET BLK
MOV AH,9
INT 21H ;输出回车、换行、数的负号
POP AX
POP BX
POP CX
RET
第 9章 程序设计的一些编程技巧
PUTDN ENDP;下述过程将 CX中无符号数转换成十进制数并输出;所用寄存器,BX,AX,DX,SI;入口参数,CX中为二进制无符号数;出口参数:缓冲区 BLK中为转换成的十进制数字的 ASCII代码;所用子程序,CHANG
GOON PROC
PUSH AX
PUSH BX
第 9章 程序设计的一些编程技巧
PUSH DX
PUSH SI
MOV BX,OFFSET BLK
MOV SI,10000
CALL CHANG
MOV SI,1000
CALL CHANG
MOV SI,100
CALL CHANG
MOV SI,10
CALL CHANG
MOV AL,30H
第 9章 程序设计的一些编程技巧
ADD AL,CL
MOV [BX],AL
MOV AL,'$'
INC BX
MOV [BX],AL
MOV DX,OFFSET BLK
MOV AH,9
INT 21H
POP SI
POP DX
POP BX
POP AX
RET
第 9章 程序设计的一些编程技巧
GOON ENDP
CHANG过程与例 9-8完全相同
CHANG PROC
RET
CHANG ENDP
COSEG ENDS
END START

第 9章 程序设计的一些编程技巧说明:
(1) 主程序中调用了 3个子程序:
① GETD:接收从键盘键入的带符号的十进制数并转换成二进制数;
② PUTDN:将二进制数相乘的积转换成十进制数并处理符号位;
③ GOON:积转换成十进制数并输出。
(2) 在子程序 GOON中调用了 CHANG,它完成的功能是:
二进制数转换成 ASCII码并输出。
第 9章 程序设计的一些编程技巧
(3) 程序中累加和乘以 10的运算没有使用乘法指令,而是用下述 3条指令来实现的:
ADD CX,CX
ADD CX,CX
ADD CX,BX
第 9章 程序设计的一些编程技巧
9.3 算 术 运 算例 9-10 内存中以 FIRST和 SECOND开始的单元中分别存放两个 16位组合的十进制 (BCD码 )数,每个数占 4个存储单元,存放时低字节存放在地址处。编程求这两个组合的十进制数的和,
并存到 THIRD开始的单元。
第 9章 程序设计的一些编程技巧此例在例 3-42中已讲述过,当时使用的是一般的数据传送指令 MOV。描述如下:
MOV BX,OFFSET FIRST
MOV SI,OFFSET SECOND
MOV DI,OFFSET THIRD
MOV CX,8
CLC
第 9章 程序设计的一些编程技巧
AGN,MOV AL,[BX]
ADC AL,[SI]
INC BX
ADC BYTE PTR[BX],0
DAA
MOV [DI],AL
INC SI
INC DI
DEC CX
JNZ AGN
HLT
第 9章 程序设计的一些编程技巧在讲述了串操作指令后,使用串操作指令 LODS重写实现这一功能的程序,描述如下:
DATA SEGMENT
FIRST DB 11H,52H,…
SECOND DB 66H,69H,…
THIRD DB 11 DUP(?)
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(? )
STACK ENDS
CODE SEGMENT
第 9章 程序设计的一些编程技巧
ASSUME CS∶ CODE,DS∶ DATA,ES∶ DATA
STR PROC FAR
START PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV SI,OFFSET FIRST
MOV BX,OFFSET SECOND
MOV DI,OFFSET THIRD
MOV CX,LENGTH THIRD
DEC CX
CLD
CLC
第 9章 程序设计的一些编程技巧
ADIT,LODS FIRST
ADC AL,[BX]
INC BX
ADC BYTE PTR[BX],0
DAA
STOS THIRD
LOOP ADIT
ADC AH,0
MOV AL,AH
STOSB
RET
STR ENDP
CODE ENDS
END START
第 9章 程序设计的一些编程技巧若要把内存单元 FIRST和 SECOND这两个字节的内容相乘,乘积放在 THIRD和 FOURTH单元中,可以用以下程序段:
MOV AL,FIRST
MUL SEC0ND
MOV THIRD,AX
第 9章 程序设计的一些编程技巧例 9-11 编制一个实现两个字 (16位 )相乘的程序。
MY_DATA SEGMENT
M1 DW 00FFH ;被乘数
M2 DW 00FFH ;乘数
P1 DW? ;存积
P2 DW?
MY_DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
第 9章 程序设计的一些编程技巧
ASSUHE CS∶ COSEG,DS∶ MY_DATA,ES∶ MY_DATA
STR PROC FAR
MULT,PUSH DS
MOV AX,0
PUSH AX
MOV AX,MY_DATA
MOV DS,AX
MOV ES,AX
MOV AX,M1
MUL M2
第 9章 程序设计的一些编程技巧
MOV P1,AX ;存结果
MOV P2,DX
RET
STR ENDP
C0SEG ENDS
END STR
第 9章 程序设计的一些编程技巧例 9-12 BCD码相乘 。
80X86中有两个未组合的十进制数相乘后的调整指令。可实现一位未组合十进制数 X与一个十进制串相乘。把串中的未组合的十进制数从低位开始送入 AL,与 X相乘,对乘积进行调整,
然后把乘积的低位与上一次的高位 (即进位部分 )相加。这样一位位乘下去,最后可得乘积。能实现上述过程的程序如下:
第 9章 程序设计的一些编程技巧
DATA SEGMENT
A DB 3,7,5,4,9 ;十进制数 94573
COUNT EQU $-A
B DB 6
C DB COUNT+1 DUP(?)
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
ASSUME CS∶ COSEG,DS∶ DATA,ES∶ DATA
STR PROC FAR
第 9章 程序设计的一些编程技巧
GO,PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV ES,AX
MOV DS,AX
CLD
MOV SI,OFFSET A
MOV DI,OFFSET C
MOV CX,COUNT
MOV BYTE PTR[DI],0
第 9章 程序设计的一些编程技巧
CYCLE,LODSB
AND AL,0FH
MUL B
AAM
ADD AL,[DI]
AAA
STOSB
MOV [DI],AH
LOOP CYCLE
RET
STR ENDP
COSEG ENDS
END GO
第 9章 程序设计的一些编程技巧例 9-13 两个两位的 BCD码相乘。
80x86中的乘法指令可实现 8位或 16位二进制数相乘或两个未组合的十进制数相乘 (要经过 AAM调整 )。但若是两个两位的用 BCD码表示的十进制数,就不能直接相乘 (即没有相应的调整指令 ),但可以用累加的方法,编一个程序来实现两位组合的十进制数乘法。算法是对被乘数累加乘数所规定的次数,被乘数的每次累加和都要经过 DAA调整;乘数每次减 1以后也要经过调整。程序如下所示:
第 9章 程序设计的一些编程技巧
NAME MULTIPLY BCD
DATA SEGMENT
FIRST DB 25H
SECOND DB 25H
THIRD DB 2 DUP(?)
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
STAPN DB 100 DUP(?)
STACK ENDS
COSEG SEGMENT
ASSUME CS∶ COSEG,DS∶ DATA,ES∶ DATA
第 9章 程序设计的一些编程技巧
STR PROC FAR
START,PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV BL,FIRST ;取乘数
MOV CL,SECDND ;取被乘数
MOV DX,0 ; DX存积
MOV AL,BL
第 9章 程序设计的一些编程技巧
AGAIN,OR AL,AL
JZ DONE ;若乘数为 0,则转 DONE
MOV AL,DL
ADD AL,CL
DAA ;结果在 AL
MOV DL,AL
MOV AL,DH
ADC AL,0 ;处理进位 (加进位 )
DAA
MOV DH,AL
MOV AL,BL
SUB AL,1 ;乘数减 1
DAS
MOV BL,AL
JMP AGAIN
第 9章 程序设计的一些编程技巧
DONE,MOV BX,OFFSET THIRD
MOV [BX],DX
RET
STR ENDP
COSEG ENDS
END START
第 9章 程序设计的一些编程技巧例 9-14 若内存的数据段中,有 — 个缓冲区 BUFFER,前两个字节是一个 16位带符号的被除数,第三、四字节是一个 16位带符号的除数。接着两个字节放商,再下来的两个字节放余数。
能实现该除法运算的程序段为
LEA BX,BUFFER
MOV AX,[BX]
CWD
IDIV 2[BX] ;带符号数除法
MOV 4[BX],AX
MOV 6[BX],DX
第 9章 程序设计的一些编程技巧
9.4 数 值 分 析
9.4.1 二分法求解方程例 9-15 用二分法求方程 x3-x-1在区间 [0,10]内的一个实根,精度为 1。
基本思想,设函数 f(x)在区间 [a,b]上连续,且 f(a).f(b)<0,根据连续函数的性质可知方程 f(x)=0在 [a,b]内一定有实根,并称 [a,b]
为方程 f(x)=0的有根区间。为明确起见,不妨假定它在 [a,b]内有惟一的实根 x*。
第 9章 程序设计的一些编程技巧把区间 [a,b] 二等分,分点为,计算函数值
,如果
b)(a21x 0
2 baf
0
2
baf?


则求的实根
2
bax *
否则,或者与异号,或者与异号。若
2 baf
0
2
baff( a )


第 9章 程序设计的一些编程技巧说明根在区间 内,这时取



2
baa,
2
baba,a
11


0bf
2
baf


说明根在区间 内,这时取


b,
2
ba
bb,
2
baa
11?

第 9章 程序设计的一些编程技巧不管出现哪一种情况,新的有根区间 [a1,b1]的长度为原有根区间
[a,b]的一半。
在新的有根区间 [a1,b1]上重复上述二分步骤,得下列有根区间序列
]b,[a]b,[a]b,[ab][ a,kk2211
其中,每个区间仅为前一个区间的一半,二分 k次以后的有根区间 [ak,bk]的长度是
a)(b
2
1ab
kkk
第 9章 程序设计的一些编程技巧在实际应用中,一般令有根区间 [ak,bk]的中点为 x*的近似值,则在二分过程中,得到下列以 x*为极限的近似根序列
)b(a21x kkk
,x,,x,x k10
由于
a)(b
2
1)a(b
2
1xx
1kkkk
*
对于预先给定的精度,只要
2ln
ε2lna)l n ( bk
便有
εxx k*
第 9章 程序设计的一些编程技巧这时,xk就是满足精度要求的近似值。程序描述如下:
DATA SEGMENT
AREAL DB 0
AREAH DB 10
HELP DB 'ROOT X=$'
DISP DB 10 DUP(?)
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
第 9章 程序设计的一些编程技巧
ASSUME CS∶ CODE,DS∶ DATA,ES∶ DATA,SS∶ STACK
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV AL,[AREAL] ;将区间下限送入 AL中
MOV AH,[AREAH] ;将区间上限送入 AH中第 9章 程序设计的一些编程技巧
LOP,SUB AH,AL
CMP AH,1 ;判断是否已达到精度
JLE EXIT ;达到则结束
ADD AH,AL ;未达到则恢复区间继续使用二分法
MOV BH,AH
ADD BH,AL
PUSH AX ;保存 AX数据
XOR AX,AX
MOV AL,BH
CBW
MOV BL,2
IDIV BL
MOV BH,AL ;将区间中点送入 BH
POP AX ;恢复 AX数据
CALL FUNCTION ; 求入口参数为 AL的函数值,出口参数 CL标识函数;值的正负第 9章 程序设计的一些编程技巧
MOV DL,AL ;保存 AL数据
MOV DH,CL ;保存 CL数据
MOV AL,BH ;求区间中点的函数值
CALL FUNCTION
MOV CH,DH
CMP CH,CL ;比较两函数值是否同号
JZ NEXT1
MOV AL,DL ;不同号则修改区间上限
MOV AH,BH
JMP LOP
NEXT1,MOV AL,BH ;同号则修改区间下限
JMP LOP
第 9章 程序设计的一些编程技巧
EXIT,PUSH AX
MOV DX,OFFSET HELP
MOV AH,09H
INT 21H
POP AX
CBW ;将区间下限扩展为 16位数
XOR CX,CX
MOV CX,AX
CALL PTDN ;显示结果
RET
START ENDP
第 9章 程序设计的一些编程技巧输出 16位二进制带符号数的子程序 PTDN与例 6-18完全一样,这里不再赘述;输出函数函数值正负的子程序;入口参数,AL为自变量;出口参数,CL为 1表示函数值为负;反之为正
FUNCTION PROC
PUSH AX
PUSH BX
PUSH DX
CBW
MOV BX,AX ;保存 AX的值
IMUL AX ;求的值第 9章 程序设计的一些编程技巧
IMUL BX
SUB AX,BX
SUB AX,1
MOV CX,AX ;将结果送入 CX
ROL CX,1 ;保存函数值的符号位
AND CX,01H
POP DX
POP BX
POP AX
RET
FUNCTION ENDP
CODE ENDS
END START
第 9章 程序设计的一些编程技巧
9.4.2 牛顿法求解方程例 9-16 用牛顿法求方程 x3-x-1=0在附近的一个实根,精度为 1。
基本思想:牛顿法是方程求根问题的一个极其基本的、十分重要的算法,它的基本思路是将非线性方程 f(x)=0逐步线性化而形成迭代公式。
设已知方程 f(x)=0的近似根 xk,将函数 f(x)在点 xk处作一阶泰勒展开,则有
)x) ( x(xf)f ( xf ( x ) kk'k
第 9章 程序设计的一些编程技巧于是方程 f(x)=0可近似地表示为
0)x)(x(xf)f( x kk'k
上式是个线性方程,记其根为 xk+1,则 xk+1就可理解为方程的一个新的近似根,即
)(xf
)f( xxx
k
'
k
k1k
这就是著名的牛顿迭代公式,相应的迭代函数是
( x )f
f( x )
x( x )
'

第 9章 程序设计的一些编程技巧程序描述如下:
DATA SEGMENT
AREAL DB 0
AREAH DB 10
HELP1 DB 'ROOT X=$'
HELP2 DB 'SIMPLE ITERATIVE FAILED!$ '
HELP3 DB 0AH,0DH,'PRESS ANY KEY TO QUIT!$ '
DISP DB 10 DUP(?)
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK
第 9章 程序设计的一些编程技巧
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
CALL ITERATIVE ;调用牛顿迭代子过程
MOV DX,OFFSET HELP3
MOV AH,09H
INT 21H
MOV AH,07H
INT 21H
RET
START ENDP
第 9章 程序设计的一些编程技巧;用牛顿法求方程实根的子程序,并显示最终结果
ITERATIVE PROC
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV BX,10 ;赋初值
MOV CX,1
LOP,MOV AX,BX
CALL FUNCTION ;原函数的函数值
CALL DFNCTION ;原函数导数的函数值
PUSH AX
MOV AX,BX
第 9章 程序设计的一些编程技巧
MOV BX,DX
XOR DX,DX
IDIV BX ;两函数值之比
POP BX
PUSH BX
SUB BX,AX ;迭代后自变量的值
INC CX
CMP CX,10000 ;是否超过规定的迭代次数
JZ NORESULT
POP AX
SUB AX,BX
CMP AX,1 ;是否已小于规定精度
JZ RESULT
CMP AX,-1 ;是否已小于规定精度
JZ RESULT ;结束迭代
ADD AX,BX
JMP LOP
第 9章 程序设计的一些编程技巧
NORESULT:POP AX ;无结果
MOV DX,OFFSET HELP2
MOV AH,09H
INT 21H
JMP EXIT
RESULT:MOV DX,OFFSET HELP1 ;显示最终结果
MOV AH,09H
INT 21H
MOV CX,BX
CALL PTDN
EXIT,POP DX
POP CX
POP BX
POP AX
RET
ITERATIVE ENDP
第 9章 程序设计的一些编程技巧输出 16位二进制带符号数的子程序与例 6-18完全一样,这里不再赘述。;求函数函数值的子程序;入口参数,AX为自变量;出口参数,BX为函数值
FUNCTION PROC
PUSH AX
MOV BX,AX
IMUL AL
IMUL BL
SUB AX,BX
SUB AX,1
MOV BX,AX
POP AX
RET
FUNCTION ENDP
第 9章 程序设计的一些编程技巧;求函数导函数函数值的子程序;入口参数,AX为自变量;出口参数,DX为函数值
DFNCTION PROC
PUSH AX
MOV DX,3
IMUL AL
IMUL DL
SUB AX,1
MOV DX,AX
POP AX
RET
DFNCTION ENDP
CODE ENDS
END START
第 9章 程序设计的一些编程技巧
9.4.3 高斯消去法解方程组例 9-17
用高斯消去法求解方程组



7x2xx2
4xx2x
14xxx4
321
321
321
基本思想:高斯消去法是一个古老的求解线性方程组的直接方法,其主要计算过程分为消元和回代两个步骤。
第 9章 程序设计的一些编程技巧
1) 消元过程设有线性方程组
bX?A
(9-1)
其中
nn2n1n
n22221
n11211
aaa
aaa
aaa
A

Tn21 )x,,x,(xX
Tn21 )b,,b,(bb
且设 A为 n阶奇异矩阵。
第 9章 程序设计的一些编程技巧为讨论问题方便,将式 (9-1)记为
(1 )(1 ) bXA? (9-2)
其中
bbA,aaA ( 1 )nijn( 1 )ij( 1 )
第 9章 程序设计的一些编程技巧
(1) 假设,则分别计算0a (1 )
11?
n),2,3,(i/aam ( 1 )11( 1 )1i1i
用 -mi1乘上方程组 (9-1)的第一个方程,再分别加到第 i个方程 (i=2,3,…,n) 上,即可消去第 2 个方程到第 n个方程中的变量 x1,
由此得下列等价方程组
( 2 )
n
( 2 )
2
( 1 )
1
n
2
1
( 2 )
nn
( 2 )
22
( 2 )
n2
( 2 )
22
( 1 )
n1
( 1 )
12
( 1 )
11
b
b
b
x
x
x
aa0
aa0
aaa


(9-3)
第 9章 程序设计的一些编程技巧简记为
( 2 )( 2 ) bXA?
其中
(9-4)
n),2,3,(ibmbb,amaa ( 1 )11i( 1 )i( 2 )i( 1 )j1i( 1 )ij( 2 )ij
第 9章 程序设计的一些编程技巧
(2) 假设,则分别计算0a (2 )
22?
n),3,4,(i/aam ( 2 )22( 2 )2i2i
用乘 -mi2上方程组 (9-3)的第 2个方程,再分别加到第 i个方程
(i=2,3,…,n) 上,即可消去第 3个方程到第 n个方程中的变量 x2,得下列等价方程组
( 3 )
n
( 3 )
3
( 2 )
2
( 1 )
1
n
3
2
1
( 3 )
nn
( 3 )
3n
( 3 )
n3
( 3 )
33
( 2 )
n2
( 2 )
23
( 2 )
22
( 1 )
n1
( 1 )
23
( 1 )
12
( 1 )
11
b
b
b
b
x
x
x
x
aa00
aa00
aaa0
aaaa


第 9章 程序设计的一些编程技巧简记为
( 3 )( 3 ) bXA?
其中
n),3,4,(ibmbb,amaa ( 2 )212i( 2 )i( 3 )i( 2 )j22i( 2 )ij( 3 )ij
第 9章 程序设计的一些编程技巧
(3) 重复上述步骤,经 n-1次消元后,得下列等价方程组
( n )
n
( 2 )
2
( 1 )
1
n
2
1
( n )
nn
( 2 )
n2
( 2 )
22
( 1 )
n1
( 1 )
12
( 1 )
11
b
b
b
x
x
x
a
aa
aaa

(9-5)
方程组 (9-5)是一个与式 (9-1)同解的上三角方程组,其求解是十分容易的。
第 9章 程序设计的一些编程技巧
2) 回代过程从方程组 (9-5)的第 n个方程开始,从下往上依次解出变量的这一过程称作回代过程,具体计算公式是,
11nn x,,x,x
.,1 )2,n1,n(i
a
)xa
(bx
,
a
b
x
( i )
ii
n
1ij
j
( i )
ij
( i )
ii
( n )
nn
( n )
n
n


第 9章 程序设计的一些编程技巧上述解法就是一般的高斯消去法,或称沿系数矩阵主对角元素的顺序消去法。这种顺序消去法,在经过前 k-1次消元后,
总是用系数矩阵中位于第 k行第 k列的元素 作除数除以第 k
行的所有元素,然后依次将第 k+1行到第 n行、第 k列上的元素全部化为零。如果此时为零或者其绝对值很小,则消元过程无法进行下去,或者将严重地影响计算精度,这是高斯顺序消去法的一大缺陷。程序描述如下:
(k)kka
(k)kka
第 9章 程序设计的一些编程技巧
DATA SEGMENT
LINE1 DB 4,1,1,14 ;增广矩阵
LINE2 DB 1,2,-1,4
LINE3 DB 2,-1,2,7
HELP1 DB 'X1=$'
HELP2 DB 0AH,0DH,'X2=$'
HELP3 DB 0AH,0DH,'X3=$'
RESULT DB 3 DUP(?)
DISP DB 10 DUP(?)
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
第 9章 程序设计的一些编程技巧
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK
START PROC FAR
PUSH DS
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV SI,OFFSET LINE2
MOV DI,OFFSET LINE1
MOV BX,4
MOV CX,2
第 9章 程序设计的一些编程技巧
LOP1,PUSH CX ;进行消元
MOV CX,4
LOP2,XOR AX,AX
MOV AL,[SI] ;消去第一列变量
IMUL BL
MOV AH,[DI]
SUB AL,AH
MOV [SI],AL
INC SI
INC DI
DEC CX
JNZ LOP2
SUB DI,4
XOR AX,AX
MOV AL,BL
MOV BL,2
第 9章 程序设计的一些编程技巧
IDIV BL
MOV BL,AL
POP CX
DEC CX
JNZ LOP1
MOV DI,OFFSET LINE3
MOV DL,1 ;化简第三行系数
MOV [DI+1],DL
MOV DL,-1
MOV [DI+2],DL
MOV SI,OFFSET LINE3
MOV DI,OFFSET LINE2
MOV BX,7
MOV CX,4
第 9章 程序设计的一些编程技巧
LOP3,XOR AX,AX
MOV AL,[SI] ;消去第二列变量
IMUL BL
MOV AH,[DI]
SUB AL,AH
MOV [SI],AL
INC SI
INC DI
DEC CX
JNZ LOP3
MOV SI,OFFSET LINE3
XOR AX,AX
MOV AL,[SI+3]
MOV DL,[SI+2]
第 9章 程序设计的一些编程技巧
CBW
IDIV DL ;求解
MOV DI,OFFSET RESULT
MOV [DI+2],AL
MOV SI,OFFSET LINE2
MOV DL,[SI+2]
IMUL DL
MOV BX,[SI+3]
SUB BX,AX
MOV AX,BX
MOV DL,[SI+1]
CBW
IDIV DL ;求解
MOV [DI+1],AL
MOV SI,OFFSET LINE1
MOV DL,[SI+1]
第 9章 程序设计的一些编程技巧
IMUL DL
MOV BX,AX
XOR AX,AX
MOV AL,[DI+3]
MOV DL,[SI+2]
IMUL DL
ADD AX,BX
MOV BX,[SI+3]
SUB BX,AX
MOV AX,BX
MOV DL,[SI]
CBW
IDIV DL ;求解
MOV [DI],AL
MOV DX,OFFSET HELP1
第 9章 程序设计的一些编程技巧
MOV AH,9
INT 21H
XOR CX,CX
MOV CL,[DI]
CALL PTDN ;显示
MOV DX,OFFSET HELP2
MOV AH,9
INT 21H
XOR CX,CX
MOV CL,[DI+1]
CALL PTDN ;显示
MOV DX,OFFSET HELP3
MOV AH,9
INT 21H
XOR CX,CX
MOV CL,[DI+2]
CALL PTDN ;显示
RET
START ENDP
第 9章 程序设计的一些编程技巧习 题 九
9.1 使用指令 REPNZ SCASB时,请问:
(1) 要求什么初始条件?
(2) 指令完成什么功能?
(3) 指令结束的条件是什么?
9.2 使用指令 REPZ CMPB时,回答习题 9.1中的三个问题。
9.3 利用 REP STOSB指令编一段程序,将自 BUFF开始的
100个连续单元初始化为 0,要求程序结构完整。
第 9章 程序设计的一些编程技巧
9.4 编程序将自 FIRST单元开始的数据块传送至自 SECOND
单元开始的区域中去,但若发现被传送数据为 0,则结束传送。
分两种情况编程序:
(1) 两数据区域不重叠。
(2) 两数据区域有重叠,SECOND单元可能在 FIRST之前,也可能在后。
9.5 内存中自 AREA1单元开始连续存放了 100个已排好序的无符号字节数,编程序将其传送到自 AREA2开始的单元中。要求传送后的数据不重复出现。
第 9章 程序设计的一些编程技巧
9.6 在 AH存放着组合的 BCD码十进制数,要求:
(1) 将 AH中的数转换成二进制数。
(2) 求 AH与 AL中数的和,并将结果转换成 ASCII码,然后在
CRT上显示出来。
9.7 编写一个程序,接收键盘输入 100个十进制数字,按下字符 T,则停止输入;利用例 9-2中的加密密码表,对输入的数字加密后存到内存缓冲区 BUFFR。
9.8 内存缓冲区 BCDBUFFR中存放着 10个字节组合的十进制数,编程序求这 10个数的和,结果送 SUM缓冲区 (占两个字节 )。
第 9章 程序设计的一些编程技巧
9.9 设 32位的被除数在 DX∶ AX中,16位的除数在 BX中且被除数和除数都为有符号数。为了在结果超出相应寄存器范围时,仍能得到正确的结果,可以分两次做除法运算。第一次用被除数的高位字除以除数,得商的高位字部分,第二次用余数和被除数的低位字部分除除数,得商的低位字部分和余数。编制实现这一功能的完整程序。