DATA SEGMENT
X DB 21, ?, 21 DUP(0)
LENX DB 0 ; X的长度
Y DB 21, ?, 21 DUP(0)
LENY DB 0 ; Y的长度
Z DB 21 DUP (0) ; 保存结果
N DB 0H ; 监视加法的进位
M DB 0H ; 监视减法的借位
STR1 DB 'INPUT X (AT MOST 20 DIGITS): $'
STR2 DB 0AH, 0DH, 'INPUT Y (AT MOST 20 DIGITS): $'
STR3 DB 0AH, 0DH, ' X + Y = $'
STR4 DB 0AH, 0DH, ' X - Y = $'
STR5 DB 0AH, 0DH, 'ERROR! PROGRAMME CANCELED...', 0AH, 0DH, '$'
DATA ENDS
STACK SEGMENT PARA STACK
DW 20H DUP(0)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK
BEGIN: MOV AX, DATA
MOV DS, AX
MOV DX, OFFSET STR1
MOV AH, 09H
INT 21H
MOV DX, OFFSET X
MOV AH, 0AH ; 获取多字节数据
INT 21H
MOV CX, 0 ; CX清零
MOV SI, OFFSET X
INC SI ; SI指向X中存储其长度的位置
MOV CL, [SI] ; 将X中的数据个数存入CX
MOV LENX, CL
CALL TESTTONUM ; 调用测试初始化子程序
MOV DX, OFFSET STR2
MOV AH, 09H
INT 21H
MOV DX, OFFSET Y ; 获取数据,同上
MOV AH, 0AH
INT 21H
MOV CX, 0
MOV SI, OFFSET Y
INC SI
MOV CL, [SI]
MOV LENY, CL
CALL TESTTONUM
MOV BL, LENX ; 判断X长度是否大于等于Y的长度
CMP BL, LENY
JAE GOOD
JMP QUIT ; 否则退出
GOOD: MOV CL, LENX
PUSH CX ; 暂存CX
MOV SI, OFFSET X ; 令SI指向X首地址
CALL COPY ; 调用复制子程序
POP CX ; CX恢复
PUSH CX ; 再次储存
CALL PRO1 ; 调用计算X+Y子程序
MOV DX, OFFSET STR3
MOV AH, 09H
INT 21H
POP CX ; CX恢复
PUSH CX ; 再次存储
CALL TOASCIISHOW ; 调用输出子程序
POP CX
PUSH CX
MOV SI, OFFSET X
CALL COPY
POP CX
PUSH CX
CALL PRO2 ; 调用计算X-Y子程序
MOV DX, OFFSET STR4
MOV AH, 09H
INT 21H
POP CX
PUSH CX
MOV N, 0H ; 避免减法结果打印出最高位的1(详细参考输出子程序)
CALL TOASCIISHOW
OVER: MOV AH, 4CH
INT 21H
TESTTONUM PROC ; 测试,初始化子程序
INC SI
PUSH SI ; 存储当前SI指向的位置(X或Y中的第一个实际数据)
LOP1: MOV AX, 0
MOV AL, [SI] ; 判断输入的不同情况
CMP AL, '0'
JB QUIT
CMP AL, 'f'
JA QUIT
CMP AL, '9'
JBE PART1
CMP AL, 'A'
JB QUIT
CMP AL, 'F'
JBE PART2
CMP AL, 'a'
JB QUIT
CMP AL, 'f'
JBE PART2
PART1: AND AL, 0FH ; 开始转化为数值
MOV [SI], AL ; 替换原始ASCII码
JMP CONTINUE1
PART2: SUB AL, 07H
JMP PART1
CONTINUE1: INC SI
LOOP LOP1
POP SI ; 恢复SI指向
DEC SI ; SI指向实际输入的位数
MOV BL, [SI]
CMP BL, 1 ; 如果只有一位,则不需要交换(由于输入时最高位存储在低地址处,所以需要交换)
JE NO
MOV CX, 0 ; 开始交换
MOV BX, 0
MOV CL, [SI]
SHR CL, 1 ; 交换循环次数是实际输入位数的一半
MOV BL, [SI] ; 开始确定最后一个数据的位置
DEC BL
MOV DI, SI
INC DI
ADD DI, BX ; 此时,DI指向最后一个数据
INC SI ; SI指向第一个数据
LOP: MOV AX, 0 ; 开始交换
MOV AL, [DI]
XCHG [SI], AL
MOV [DI], AL
INC SI
DEC DI
LOOP LOP
RET
QUIT: MOV DX, OFFSET STR5 ; 错误信息
MOV AH, 09H
INT 21H
JMP OVER
NO: RET
TESTTONUM ENDP
COPY PROC ; 复制子程序
INC SI
INC SI ; SI指向要复制的第一个数据
MOV DI, OFFSET Z
LOP2: MOV AX, 0 ; 开始复制到Z中
MOV AL, [SI]
MOV [DI], AL
INC SI
INC DI
LOOP LOP2
RET
COPY ENDP
PRO1 PROC ; 计算X+Y子程序
MOV SI, OFFSET Z
MOV DI, OFFSET Y
INC DI
INC DI ; DI指向Y中的第一个数据
MOV CX, 0
MOV CL, LENY ; 先循环LENY次(位数相同的部分)
LOP3: MOV BX, 0
MOV BL, [DI]
ADD BL, N ; N为低位向本位的进位(第一次值为0)
ADD [SI], BL
MOV BL, [SI]
CMP BL, 0FH ; 如果本位大于F,则设置进位N为1
JBE NOUP1 ; 否则跳转
MOV N, 1H
JMP UP1
NOUP1: MOV N, 0H ; 无进位,设置N为0
UP1: INC SI
INC DI
LOOP LOP3
MOV AL, LENX
SUB AL, LENY ; 再循环LENX-LENY次(循环X比Y多出来的那部分位数)
MOV CL, AL
JCXZ OUT1
LOP4: ADD BYTE PTR [SI], 0
MOV BL, N ; 同样加上当前进位N
ADD [SI], BL
MOV BL, [SI]
CMP BL, 0FH ; 有进位时,N置1
JBE NOUP2
MOV N, 1H
JMP UP2
NOUP2: MOV N, 0H ; 无进位时,N置0
UP2: INC SI
LOOP LOP4
OUT1: RET
PRO1 ENDP
PRO2 PROC ; 计算X-Y子程序
MOV SI, OFFSET Z
MOV DI, OFFSET Y
INC DI
INC DI
MOV CX, 0H
MOV CL, LENY ; 先循环LENY次(位数相同的部分)
LOP5: MOV BX, 0H
MOV BL, [DI]
ADD BL, M ; 将减数加上低位向本位的借位M(第一次为0)
CMP BL, [SI] ; 如果减数小于等于被减数,则无借位(M置0)
JBE NODOWN1
MOV AL, [SI]
OR AL, 10H ; 否则,从高位借1,被减数加上10H(同ADD 10H)
MOV [SI], AL
MOV M, 1H ; 有借位,M置1
JMP DOWN1
NODOWN1:MOV M, 0H
DOWN1: SUB [SI], BL
INC SI
INC DI
LOOP LOP5
MOV AL, LENX
SUB AL, LENY
MOV CL, AL ; 再循环LENX-LENY次(循环X比Y多出来的那部分位数)
JCXZ OUT2
LOP6: SUB BYTE PTR [SI], 0H
MOV BL, M
CMP BYTE PTR [SI], BL ; 如果此位比借位还小,则继续借位(即此位为0时)
JAE NODOWN2
MOV AL, [SI]
OR AL, 10H
MOV [SI], AL
MOV M, 1H
JMP DOWN2
NODOWN2:MOV M, 0H ; 无借位,M置0
DOWN2: SUB [SI], BL
INC SI
LOOP LOP6
OUT2: RET
PRO2 ENDP
TOASCIISHOW PROC ; 输出函数
MOV BL, N
CMP BL, 0H ; 如果N为1,则在结果最前面打印一个'1'(即结果的最高位也存在进位)
JE OVERF ; 检测减法的最高位溢出
MOV DL, '1'
MOV AH, 02H
INT 21H
OVERF: MOV BL, M ; 如果M为1,则在结果最前面打印一个'_'(即结果的最高位也存在借位)
CMP BL, 0H
JE NORMAL
MOV DL, '_'
MOV AH, 02H
INT 21H
NORMAL: MOV SI, OFFSET Z
MOV BX, 0
MOV BL, LENX ; 此处为从Z的高地址向低地址打印(结果从高位到低位显示)
ADD SI, BX
DEC SI
LOP7: MOV AX, 0
MOV AL, [SI]
AND AL, 0FH ; 保留一位有效数值(每位只有一个数字)
CMP AL, 0AH ; 开始转化为ASCII码
JB CONTINUE2
ADD AL, 07H
CONTINUE2: ADD AL, 30H
MOV DX, 0
MOV DL, AL
MOV AH, 02H
INT 21H
DEC SI
LOOP LOP7
MOV DL, 'H'
MOV AH, 02H
INT 21H
RET
TOASCIISHOW ENDP
CODE ENDS
END BEGIN