汇编Q1:大数相乘

注:此博客不再更新,所有最新文章将发表在个人独立博客limengting.site。分享技术,记录生活,欢迎大家关注

Q1、大数相乘。要求实现两个十进制大整数的相乘,输出乘法运算的结果。

文章首发于我的个人博客
汇编实现大数相乘
转载请注明出处

.386
.model flat, stdcall
option casemap : none

includelib msvcrt.lib
include msvcrt.inc

endl equ <0DH,0AH>
.data
;numcharA/B最多容纳100个字节的字符,全部初始化为0
numCharA byte 100 dup(0)
numCharB byte 100 dup(0)
resultChar byte 200 dup(0)
numIntA dword 100 dup(0)
numIntB dword 100 dup(0)
result dword 200 dup(0)
;输入的格式
inputMsg byte "please input a large multiplier: ",0
szFmt_s byte "%s", 0
szFmt_d byte "%d", 0
;输出的格式
outputMsg byte "the result is %s",endl,0
outputMsg2 byte "the result is %s%s",endl,0
;把lenthA/B/C初始化为0
lengthA dword 0
lengthB dword 0
lengthC dword 0
;符号标志位,初始值为0,表示为正,为1表示为负	
radix dword 10
negativeFlag byte 0
negativeImg byte "-"

.code
;=================================================================================
;字符串中的内容依次入栈,然后出栈,实现反转功能,并将byte型数组转化为dword型数组
;反转前为numChar,为byte型数组,每个byte存储字符'0'~'9',反转后为numInt,为dword型数组,每个dword存储数字0~9
;SS:ESP指示处于栈中的位置
str2int_reverse proc far C numChar:ptr byte, numInt:ptr dword, len:dword
	mov ecx, len ;字符串长度即为循环的次数
	mov esi, numChar
L1:
	movzx eax, byte ptr [esi] ;高位0扩展
	sub eax, 30H ;30H对应'0',字符'0'~'9' - '0'得到数字0~9
	push eax ;eax入栈
	inc esi ;esi++
	loop L1 ;把byte数组numChar全部入栈,最高位先入栈,最低位最后入栈

	mov ecx, len
	mov esi, numInt
L2:
	pop eax
	mov dword ptr [esi], eax
	add esi, 4
	loop L2	;把byte数组numChar依次出栈存到dword数组中,最低位先出栈,最高位最后出栈

	ret
str2int_reverse endp


;===============================================================
;字符串中的内容依次入栈,然后出栈,实现反转功能,并将dword型数组转化为byte型数组
;反转前为numInt,为dword型数组,每个dword存储数字0~9,反转后为numChar,为byte型数组,每个byte存储字符'0'~'9'
;SS:ESP指示处于栈中的位置
int2str_reverse proc far C uses eax esi ecx 
	mov ecx, lengthC ;结果的长度为循环的次数
	mov esi, 0 
L1:
	mov eax, dword ptr result[4 * esi] 
	add eax, 30H ;数字0~9 + '0'得到字符'0'~'9'
	push eax
	inc esi
	loop L1 ;把dword数组numInt全部入栈,最高位先入栈,最低位最后入栈

	mov ecx, lengthC
	mov esi, 0
L2:
	pop eax
	mov byte ptr resultChar[esi], al ;依次出栈,把低八位存在resultChar的对应位置中,最低位先出栈,存在resultChar的最低位中
	inc esi
	loop L2
	
	ret
int2str_reverse endp


;=======================================================================================================
;将数组A的长度赋给lengthA,并调用str2int_reverse
getStringALen proc far C uses eax
	.if numCharA == 2DH	;2DH对应ASCII码为'-'
		xor negativeFlag, 1 
		invoke crt_strlen, addr (numCharA + 1) ;跳过负号求字符串长度,结果在eax中
		mov lengthA, eax
		invoke str2int_reverse, addr (numCharA + 1), addr numIntA, lengthA ;字符串反转,且byte数组转dword数组
	.else ;如果A为正数
		invoke crt_strlen, addr numCharA ;求字符串长度,结果放在eax中
		mov lengthA, eax
		invoke str2int_reverse, addr numCharA, addr numIntA, lengthA
	.endif
	ret
getStringALen endp

;将数组B的长度赋给lengthB,并调用str2int_reverse
getStringBLen proc far C uses eax
	.if numCharB == 2DH	;2DH对应ASCII码为'-'
		xor negativeFlag, 1 
		invoke crt_strlen, addr (numCharB + 1) ;跳过负号求字符串长度,结果在eax中
		mov lengthB, eax
		invoke str2int_reverse, addr (numCharB + 1), addr numIntB, lengthB ;字符串反转,且byte数组转dword数组
	.else ;如果A为正数
		invoke crt_strlen, addr numCharB ;求字符串长度,结果放在eax中
		mov lengthB, eax
		invoke str2int_reverse, addr numCharB, addr numIntB, lengthB
	.endif
	ret
getStringBLen endp
;=============================================================================================================
;模拟手算的大数相乘算法
high_multiply proc far C uses eax ecx esi ebx
	mov ebx, -1
OuterLoop: 
	inc ebx
	cmp ebx, lengthA
	jnb endLoop1 ;如果ebx >= lengthA,结束循环
	xor ecx, ecx
InnerLoop:
	xor edx, edx
	mov eax, dword ptr numIntA[4 * ebx]
	mul numIntB[4 * ecx] ;numIntA[4 * ebx] * numIntB[4 * ecx]结果放在EDX:EAX中,最大9*9 = 81也不会超过8个字节,所以结果只在EAX中
	mov esi, ecx
	add esi, ebx ;esi = ecx + ebx,即两个下标之和
	add result[4 * esi], eax ;把两个位相乘的结果加到result的相应位上
	inc ecx
	cmp ecx, lengthB 
	jnb OuterLoop ;无符号数ecx>=lengthB时,下标超过lengthB - 1时跳出内层循环重新进行外层循环
	jmp InnerLoop	;不超过则继续进行内层循环
endLoop1:
	mov ecx, lengthA
	add ecx, lengthB
	inc ecx	;ecx = lengthA + lengthB + 1
	mov esi, offset lengthC
	mov [esi], ecx ;将ecx赋给lengthC

	xor ebx, ebx
CarryCul:
	cmp ebx, ecx
	jnb endLoop2 ;ebx >= ecx跳到endLoop2,跳出求进位的循环
	mov eax, result[4  * ebx]
	xor edx, edx
	div radix
	add result[4 * ebx + 4], eax ;result[i+1] += result[i]/10
	mov result[4 * ebx], edx ;result[i] = result[i] % 10
	inc ebx
	jmp CarryCul
endLoop2: 
	mov ecx, lengthC ;让MoveZero从最后一位开始检查
MoveZero:
	cmp dword ptr result[4 * ecx], 0
	jnz endwhile1 ;result的末位不为0
	dec ecx ;每检测到一个0,实际长度减一 
	jmp MoveZero
endwhile1:
	inc ecx ;实际长度为最大下标加一
	mov esi, offset lengthC
	mov [esi], ecx ;将ecx赋给lengthC
	invoke int2str_reverse ;将dword数组逆序并转化为byte数组

	ret
high_multiply endp

;======================================================================================
;主函数
main proc
	;键盘分别输入A和B,并存储为byte数组
	invoke crt_printf, addr inputMsg
	invoke crt_scanf, addr szFmt_s, addr numCharA 
	invoke crt_printf, addr inputMsg
	invoke crt_scanf, addr szFmt_s, addr numCharB

	invoke getStringALen ;将数组A的长度赋给lengthA,并调用str2int_reverse
	invoke getStringBLen ;将数组B的长度赋给lengthB,并调用str2int_reverse
	
	invoke high_multiply ;调用大数乘法子函数

	.if negativeFlag == 1
		invoke crt_printf, addr outputMsg2,addr negativeImg, addr resultChar
	.else 
		invoke crt_printf, addr outputMsg, addr resultChar
	.endif

	ret
main endp
end main
  • 12
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
汇编语言中,判断无符号乘法是否溢出可以通过检查乘法结果是否超出了所使用的寄存器的位数来实现。以下是一种常见的方法: 1. 使用无符号乘法指令进行乘法运算。例如,对于x和y两个无符号数进行乘法,可以使用`MUL`指令,将x乘以y的结果存储在结果寄存器中。 2. 检查结果是否超出了所使用的寄存器的位数。如果结果超出了寄存器的位数限制,则说明发生了溢出。 具体的实现方法取决于所使用的汇编语言和处理器架构。下面是一个示例,在x86汇编语言中使用32位无符号乘法(`MUL`指令)进行溢出判断的示例: ```assembly ; 假设x和y分别存储在eax和ebx寄存器中 mov eax, x mov ebx, y mul ebx ; 无符号乘法,结果存储在edx:eax中 ; 检查结果是否溢出 test edx, edx ; 检查edx寄存器的值是否为0 jnz overflow ; 如果edx不为0,则发生了溢出 ; 在这里处理未发生溢出的情况 overflow: ; 在这里处理溢出的情况 ``` 在示例中,使用`MUL`指令进行无符号乘法运算,将结果存储在edx:eax寄存器中。然后,通过检查edx寄存器的值是否为0来判断是否发生了溢出。如果edx寄存器不为0,则说明溢出发生了。根据需要,可以在`overflow`标签处处理溢出情况,或在未发生溢出的情况下执行其他操作。 请注意,具体的实现方法可能因使用的汇编语言和处理器架构而有所不同。上述示例仅作为一种常见的方法,具体实现时请参考相关的汇编语言和处理器架构文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值