汇编语言实现两个多位十进制数相减实验
程序员文章站
2024-02-02 15:50:10
...
将两个多位十进制数相减,要求被减数,减数均以 ASCII码形式按顺序存放在以DATA1和DATA2为首的5个内存单元中(低位在前),结果送回DATA1处。
1.这个程序就是实现两个多位数相减功能,经过查阅资料分析得到,有两种方法有一位位相减和合成一个整体后再相减。一位位相减要利用sbb带借位的减法实现功能,这样计算得到的结果就是正确的了。其次这种方法,要进行分类讨论,比较被减数和减数的大小才能得到正确的结果。如果减数比被减数大的话要先显示一个负号,再输出结果。
2.合成一个整体麻烦的难点在于要合成一个数,利用汇编语言合成一个数的思路其实是很类似的,只要学会一个其余都问题不大了。
我写了三种,第一种最简单,无符号数,不输入。
DATAS SEGMENT
;此处输入数据段代码
A db 4 dup(?)
length_A equ $-A
B db 4 dup(?)
buf1 db '-','$'
buf2 db '=','$'
buf3 db 'Please input two number:',0dh,0ah,'$'
buf4 db 'A=','$'
buf5 db 'B=','$'
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
dw 50 dup(?)
top label byte
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
mov ax,stacks
mov ss,ax
mov sp,offset top
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
;A部分
;显示A中的数据
lea dx,buf4
mov ah,09h
int 21h
mov cx,length_A
lea si,A
call input
call hui_che
lea dx,buf5
mov ah,09h
int 21h
mov cx,length_A
lea si,B
call input
call hui_che
mov cx,length_A
lea di,A
Loop_show_A:
mov al,[di]
call show_ascii
inc di
loop Loop_show_A
lea dx,buf1
mov ah,09h
int 21h
;B部分
;显示B中的数据
mov cx,length_A
lea di,B
Loop_show_B:
mov al,[di]
call show_ascii
inc di
loop Loop_show_B
lea dx,buf2
mov ah,09h
int 21h
;减法运算部分
mov si,offset A
mov di,offset B
mov cx,length_A
compare:;比较a和b哪一个数据更大
mov al,[si]
cmp al,[di]
ja a_b;大于的话直接比较
jb b_a;小于的话b-a
je keep_compare;继续比较下一位
keep_compare:
dec cx
inc si
inc di
jmp compare
b_a:
mov dl,'-';显示负号
mov ah,02h
int 21h
;应该是b-a
call sub_B_A
mov si,offset A
mov cx,length_A
jmp Loop_show_result
a_b:
call sub_A_B
mov si,offset A
mov cx,length_A
Loop_show_result:
mov al,[si]
call show_ascii
inc si
loop Loop_show_result
;结束部分
jmp end_pro
input proc near
input_loop:
mov ah,01h
int 21h
mov [si],al
inc si
loop input_loop
exit:
ret
input endp
show_ascii proc near;显示ascii码
mov dl,al
mov ah,02h
int 21h
ret
show_ascii endp
sub_A_B proc near
mov bx,length_A
su1:
sub byte ptr[si+bx-1],30h;最后一位数据,转换为十进制
sub byte ptr[di+bx-1],30h
dec bx
jnz su1
mov si,offset A
add si,length_A-1
mov di,offset B
add di,length_A-1
mov cx,length_A;包括进位一共有位数
clc
su2:
mov al,[si]
mov bl,[di]
sbb al,bl;带借位相减
aas;非压缩BCD码格式的调整
mov [si],al;结果被送到di作为被减数被减数区域
dec si
dec di;指向下一位
loop su2;循环
mov bx,length_A
mov si,offset A
mov di,offset B
su3:
add byte ptr [si+bx-1],30h
;add byte ptr [di+bx-1],30h
dec bx
jnz su3
ret
sub_A_B endp
sub_B_A proc near
mov bx,length_A
su1:
sub byte ptr[si+bx-1],30h;最后一位数据,转换为十进制
sub byte ptr[di+bx-1],30h
dec bx
jnz su1
mov si,offset B
add si,length_A-1
mov di,offset A
add di,length_A-1
mov cx,length_A;包括进位一共有位数
clc
su2:
mov al,[si]
mov bl,[di]
sbb al,bl;带借位相减
aas;非压缩BCD码格式的调整
mov [di],al;结果被送到被减数区域
dec si
dec di;指向下一位
loop su2;循环
mov bx,length_A
mov si,offset B
mov di,offset A
su3:
add byte ptr [di+bx-1],30h
;add byte ptr [di+bx-1],30h
dec bx
jnz su3
ret
sub_B_A endp
hui_che proc near
mov dl,0ah
mov ah,02h
int 21h
ret
hui_che endp
end_pro:
MOV AH,4CH
INT 21H
CODES ENDS
END START
第二种和第一种唯一的区别是加入了输入:
DATAS SEGMENT
;此处输入数据段代码
A db 33h,38h,39h,36h;3896
length_A equ $-A
B db 31h,32h,33h,35h;1235
buf1 db '-','$'
buf2 db '=','$'
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
dw 50 dup(?)
top label byte
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
mov ax,stacks
mov ss,ax
mov sp,offset top
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
;A部分
;显示A中的数据
mov cx,length_A
lea di,A
Loop_show_A:
mov al,[di]
call show_ascii
inc di
loop Loop_show_A
lea dx,buf1
mov ah,09h
int 21h
;B部分
;显示B中的数据
mov cx,length_A
lea di,B
Loop_show_B:
mov al,[di]
call show_ascii
inc di
loop Loop_show_B
lea dx,buf2
mov ah,09h
int 21h
;减法运算部分
mov si,offset A
mov di,offset B
mov cx,length_A
compare:;比较a和b哪一个数据更大
mov al,[si]
cmp al,[di]
jg a_b;大于的话直接比较
jb b_a;小于的话b-a
je keep_compare;继续比较下一位
keep_compare:
dec cx
inc si
inc di
jmp compare
b_a:
mov dl,'-';显示负号
mov ah,02h
int 21h
;应该是b-a
call sub_B_A
mov si,offset A
mov cx,length_A
jmp Loop_show_result
a_b:
call sub_A_B
mov si,offset A
mov cx,length_A
Loop_show_result:
mov al,[si]
call show_ascii
inc si
loop Loop_show_result
;结束部分
jmp end_pro
show_ascii proc near;显示ascii码
mov dl,al
mov ah,02h
int 21h
ret
show_ascii endp
sub_A_B proc near
mov bx,length_A
su1:
sub byte ptr[si+bx-1],30h;最后一位数据,转换为十进制
sub byte ptr[di+bx-1],30h
dec bx
jnz su1
mov si,offset A
add si,length_A-1
mov di,offset B
add di,length_A-1
mov cx,length_A;包括进位一共有位数
clc
su2:
mov al,[si]
mov bl,[di]
sbb al,bl;带借位相减
aas;非压缩BCD码格式的调整
mov [si],al;结果被送到di作为被减数被减数区域
dec si
dec di;指向下一位
loop su2;循环
mov bx,length_A
mov si,offset A
mov di,offset B
su3:
add byte ptr [si+bx-1],30h
;add byte ptr [di+bx-1],30h
dec bx
jnz su3
ret
sub_A_B endp
sub_B_A proc near
mov bx,length_A
su1:
sub byte ptr[si+bx-1],30h;最后一位数据,转换为十进制
sub byte ptr[di+bx-1],30h
dec bx
jnz su1
mov si,offset B
add si,length_A-1
mov di,offset A
add di,length_A-1
mov cx,length_A;包括进位一共有位数
clc
su2:
mov al,[si]
mov bl,[di]
sbb al,bl;带借位相减
aas;非压缩BCD码格式的调整
mov [di],al;结果被送到被减数区域
dec si
dec di;指向下一位
loop su2;循环
mov bx,length_A
mov si,offset B
mov di,offset A
su3:
add byte ptr [di+bx-1],30h
;add byte ptr [di+bx-1],30h
dec bx
jnz su3
ret
sub_B_A endp
end_pro:
MOV AH,4CH
INT 21H
CODES ENDS
END START
最后一种是加入了对于有符号数的处理,可以输入并且输出有符号数,直接将减数和被减数相减即可。
DATAS SEGMENT
;此处输入数据段代码
buf dw 2 dup(?)
tmp db 10 dup(?)
buf1 db '-','$'
buf2 db '=','$'
buf3 db 'Please input two number:',0dh,0ah,'$'
buf4 db 'A=','$'
buf5 db 'B=','$'
buf6 db 0ah,'The character is out of range, Try again:',0dh,0ah,'$'
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
dw 50 dup(?)
top label byte
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
mov ax,stacks
mov ss,ax
mov sp,offset top
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
;A部分
;显示A中的数据
lea dx,buf4
mov ah,09h
int 21h
mov si,0;si作为下标
call prepare_input
call input
add si,02h
lea dx,buf5
mov ah,09h
int 21h
call prepare_input
call input
;显示计算数据
mov si,0
mov ax,buf[si]
add si,02h
call show_ascii
mov dl,'-'
mov ah,02h
int 21h
mov ax,buf[si]
call show_ascii
mov dl,'='
mov ah,02h
int 21h
;减法运算部分
mov si,0
mov ax,buf[si]
add si,02h
mov dx,buf[si]
sub ax,dx
call show_ascii
jmp end_pro
prepare_input proc near
mov bx,10
mov bp,0
mov dx,0
ret
prepare_input endp
input proc near
push cx
get_char:
mov ah,01h
int 21h
cmp al,'-';判断是否为负数
jz nagetive
cmp al,0dh;判断是否为回车
jz process_1
cmp al,' ';判断是否为空格
jz process_1
cmp al,30h
jl mistake
cmp al,39h;大于9
ja judge1
jmp process_2
judge1:
cmp al,41h;表示在39<x<41的数
jb mistake
cmp al,80h;表示>46即超过F的数
ja mistake
jmp process_2
mistake:
mov dx,offset buf6
mov ah,9h
int 21h
jmp get_char
nagetive:
mov bp,1;bp作为符号位
jmp get_char
process_2:
push ax;
mov ax,dx
mul bx;乘以10,以十进制存储
mov dx,ax;数据保存在dx中
pop ax
sub al,30h
mov ah,0
add dx,ax
jmp get_char
process_1:
cmp bp,1
jnz save
neg dx;取负命令0-原数据
save:
mov buf[si],dx;将处理好的数据存入num中去
mov bp,0;bp位清零
mov dl,0dh;回车换行重新输入
mov ah,2
int 21h
mov dl,0ah
int 21h
exit:
pop cx
ret
input endp
show_ascii proc near
test ax,1000h;与命令
jz pre_show;不是负数
push ax
mov dl,'-';是负数的情况,先显示负号
mov ah,02h
int 21h
pop ax
neg ax
pre_show:
mov di,0
mov dx,0
mov bx,10
mid_show:
div bx;十六进制转十进制
add dl,30h;余数部分作为结果
mov tmp[di],dl
inc di
cmp ax,0;判断商是否为0,是则表示转换完成
jz last_show
mov dx,0;余数部分清零
jmp mid_show
last_show:
mov dl,tmp[di-1];dl为待输出字符的ascii码
mov ah,2
int 21h
dec di
jnz last_show
ret
show_ascii endp
end_pro:
MOV AH,4CH
INT 21H
CODES ENDS
END START
用汇编实现一个简单的多位数相减起始挺复杂的,第一种方法的缺点在于,首先减数和被减数的位数要相同,优点在于不用受位数的限制可以输入任意多位而不会发生溢出。方法二的缺点在于输入位数不能超过有符号数的范围,优点相减结果不需要讨论,可以直接输出结果。这个程序也是在一步步的改进中更加完善,起始功能是很简单的,后来增加了输入输出,后面发现没有对有符号数的处理,同样后面也改进了。我默认是输入4位数,后续可以改进的功能是输入任意多位数,以及输入保护。
下一篇: 代码摘录
推荐阅读