汇编实现大数相乘

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
.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
谢谢小天使请我吃糖果
0%