1.1实验内容
实现两个十进制大整数的相乘(100位以上),输出乘法运算的结果。
1.2实验环境
Microsoft Visual Studio 2017+masm 32
1.3实验思路
1.3.1数据读入
大数相乘由于输入的数字过大而不能用一个dword来存储,所以需要使用数组来存取每一位,每一位大小范围在0-9中,按位读取输入,所以首先需要按照字符读取输入,将读入的两个数存储为两个字符数组中。
;键盘分别输入A和B,并存储为byte数组
invoke printf, offset inputMsg
invoke scanf,addr input,addr numCharA
invoke printf,offset inputMsg
invoke scanf,addr input,addr numCharB
1.3.2 将字符转为数字并反转存储
由于读入数据的是字符,所以需要先将字符转为数字,才能进行乘法,其次在大数相乘中,我们模拟手算乘法的过程,即乘数之间从低位向高位相乘并按位存储,再进行进位处理。所以,在转换为数字的过程中,我们通过将字符处理为数字后压栈,再依次退栈存储到数字数组中,实现将数字反转,这样再模拟乘法过程中可以从数组开始循环至数组结束。
invoke strlen,numChar
mov len,eax
mov ecx,len
L3:
;eax=esi[i]
movzx eax,byte ptr[esi]
;减去'0',得到数字0-9
sub eax,30H
;压栈
push eax
;esi=numChar[i+1]
inc esi
loop L3
mov ecx,len
mov esi,numInt
L4:
;从栈中弹出数据,依次存储到numInt中,达到反序的目的
pop eax
mov dword ptr[esi],eax
;esi+4,因为numInt为dword数组,4个偏移量为一个数据
add esi,4
loop L4
;再次调用strlen,使eax=len,返回时从eax即可读出len的值
invoke strlen,numChar
1.3.3 模拟乘法
模拟乘法的过程为模拟手算乘法的过程,即x的第i位与y的第j位相乘时,结果存储到结果的第i+j位。
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
1.3.4 进位
从低位到高位依次将结果的第i+1位加上第i位除10的结果,第i位等于第i位模10的结果。即result[i+1]+=result[i]/10,result[i]+=result[i]%10。
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从最后一位开始检查
1.3.5 清0
当i位数与j位数相乘时,最终结果不一定是i+j位,从最高位依次检测结果数组中的值是否为0,为0则长度减1。
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
1.3.6结果转为字符再输出
由于计算的结果也是反序存储在结果数组中,所以需要将结果数组反转并且转换位字符数组才能输出,所以采用和1.3.2类似的方法,将数字转为字符并压栈,循环结束后将字符依次退栈存储到结果中,最后输出字符串即可。
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
1.3.6 对负数进行处理
由于读入数据是一个一个字符的读入,所以如果读入的数字第一位为“-”,维护一个negativeFlag初始为0。若读入一个符号,则将其异或,则0变1,再有一个负号则1变0,当negativeFlag为1时,输出时则在结果之间输出负号。
;esi=numChar首地址
mov esi,numChar
;eax=esi[0]
movzx eax,byte ptr[esi]
;Symbol=eax,判断numChar第一个字符是否为负号
mov Symbol,eax
.if Symbol==2DH
;为负数,negativeFlag异或1
xor negativeFlag,1
;调用strlen得到numChar的长度
invoke strlen,numChar
;减去负号
sub eax,1
mov len,eax
mov ecx,len
;esi=numChar[1]
inc esi
1.4实验结果
文章来源:https://www.toymoban.com/news/detail-486030.html
文章来源地址https://www.toymoban.com/news/detail-486030.html
到了这里,关于汇编语言实验——大数相乘的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!