汇编语言实现两个多位十进制数相减实验

将两个多位十进制数相减,要求被减数,减数均以 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位数,后续可以改进的功能是输入任意多位数,以及输入保护。

  • 10
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值