欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 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位数,后续可以改进的功能是输入任意多位数,以及输入保护。