完美数和算术表达式

实验内容

  • 编程实现找出k个完美数,正整数n成为完美数是指n等于其所有真因子的和。如 6=1+2+3, 28=1+2+4+7+14
  • 3个整数数组中,对每个数组统计被3除余数分别为012的整数个数,并在屏幕显示统计结果。
  • 给定内存中整数数组,及给定一个参考整数Key,试调整数组使得小于Key的数存放在数组左边,大于或等于Key数放在数组右边,试编写程序完成上述任务并输出分界位置及数组。
  • 从键盘读取一串字符S,该字符串包含一个简单算术表达式(含两个正整数(如:3434*45)的四则运算),试编程解析该字符串,并实现其语义。
  • 正整数的2的幂次方表示:任何一个正整数都可以表示成2的幂次方和。如15=23+22+2+20

我的代码

输出k个完美数

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
include irvine32.inc
.data
msg1 db 'Yes',0
msg2 db 'No',0
msg3 db '//',0
msg db '输入整数K以输出k个完美数:',0
.code
main proc
lea edx,msg
call writestring
call crlf
call readint
push eax
call printperfnum

exit
main endp

;push n [ebp+8]=n
;return eax
isperfnum proc
push ebp
mov ebp,esp
sub esp,4
pushad

mov edi,[ebp+8] ;edi=n
mov ebx,edi
shr ebx,1 ;ebx=n/2
mov ecx,1 ;ecx=sum
mov esi,2 ;esi=factor

again:
cmp esi,ebx
jg next
mov edx,0
mov eax,edi
div esi
cmp edx,0
jnz L
add ecx,esi
L:
inc esi
jmp again

next:
cmp ecx,edi
jnz L0
mov eax,1
jmp final
L0:
mov eax,0

final:
mov [ebp-4],eax
popad
mov eax,[ebp-4]
pop ebp
add esp,4
ret 4
isperfnum endp

;push k [ebp+8]=k
;return nothing
printperfnum proc
push ebp
mov ebp,esp
pushad

mov esi,0 ;esi=count
mov ebx,6 ;ebp=n
mov ecx,[ebp+8] ;ecx=k
again:
cmp esi,ecx
jge final
push ebx
call isperfnum
cmp eax,0
jz L
mov eax,ebx
call writedec
call crlf
inc esi
L:
inc ebx
jmp again

final:
popad
pop ebp

ret
printperfnum endp

end main

/*
试编程实现找出k个完美数,正整数n成为完美数是 指n等于其所有真因子的和。
如 6=1+2+3, 28=1+2+4+7+14

printPerfNumbers(k):
count=0;
n=6;
while(count < k) {
if isPerfNumber(n) {
print(n);
count++;
}
n++;
}
isPerfNumber(n):
sum=1;
factor=2;
while(factor<=n/2) {
if n% factor ==0 {
sum = sum + factor;
}
factor=factor+1;
}
if sum==n { return 1;}
return 0;

printPerfNumbers(k):
count=0;
n=6;
while(count < k) {
if isPerfNumber(n) {
print(n);
count++;
}
n++;
}
*/

模3余数统计

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
include irvine32.inc
.data
a dd 77,2,45,33
b dd 1,23,45,33, 4,8
x dd 49,3,5,75,69,23,78
zero dd ?
one dd ?
two dd ?
msg1 db 'A:',0
msg2 db 'B:',0
msg3 db 'C:',0
.code
main proc
push offset a
push lengthof a
lea edx,msg1
call writestring
call mod3count

push offset b
push lengthof b
lea edx,msg2
call writestring
call mod3count

push offset x
push lengthof x
lea edx,msg3
call writestring
call mod3count

exit
main endp

;push offset a
;push lengthof a
;call mod3count
;return nothing
mod3count proc
push ebp
mov ebp,esp
pushad

mov zero,0
mov two,0
mov one,0
mov ebx,[ebp+12] ;ebx为数组首地址
mov edi,[ebp+8] ;edi为数组元素个数
mov esi,0
again:
cmp esi,edi
jge print
mov eax,[ebx+esi*4]
mov edx,0
mov ecx,3
div ecx
cmp edx,0
jne L1
L0:
inc zero
jmp next
L1:
cmp edx,1
jnz L2
inc one
jmp next
L2:
inc two
jmp next
next:
inc esi
jmp again
print:
mov eax,zero
call writedec
mov eax,' '
call writechar
mov eax,one
call writedec
mov eax,' '
call writechar
mov eax,two
call writedec
mov eax,' '
call writechar

final:
call crlf
popad
pop ebp

ret 8
mod3count endp

end main

简单分组

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
include irvine32.inc
.data
a dd 12,89,4,33,154,754,169,47,4,865,19
b dd 20 dup (?)
key dd 123
flag dd -1
msg1 db '|| ',0
msg2 db 'key=',0
.code
main proc
push flag
push offset a
push lengthof a
call print

lea edx,msg2
call writestring
mov eax,key
call writeint
call crlf

push offset a
push offset b
push lengthof a
push key
call movarr

mov flag,eax
push flag
push offset b
push lengthof a
call print

exit
main endp

;push flag
;push offset arr
;push len
;call print
;return nothing
print proc
push ebp
mov ebp,esp
pushad

mov ebx,[ebp+12]
mov esi,0
mov edi,[ebp+16]
dec edi
again:
cmp esi,[ebp+8]
jge final
mov eax,[ebx+4*esi]
call writeint
mov al,' '
call writechar
cmp edi,esi
jnz next
lea edx,msg1
call writestring
next:
inc esi
jmp again

final:
call crlf
popad
pop ebp

ret 12
print endp

;push offset a
;push offset b
;push lengthof a
;push key
movarr proc
push ebp
mov ebp,esp
sub esp,4
pushad

mov ebx,[ebp+20];ebx=offset a
mov ecx,[ebp+16];ecx=offset b
mov esi,0
mov edx,0
mov edi,[ebp+12]
dec edi
again:
mov eax,[ebp+12]
cmp esi,eax
jge final
mov eax,[ebx+esi*4]
cmp eax,[ebp+8]
jge next
mov [ecx+edx*4],eax
inc edx
inc esi
jmp again

next:
mov [ecx+edi*4],eax
dec edi
inc esi
jmp again

final:
mov [ebp-4],edx
popad
mov eax,[ebp-4]
add esp,4
pop ebp

ret 16
movarr endp

end main

幂次方表示

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
include irvine32.inc
.data
num dd 15
msg1 db '2^',0
msg2 db '请输入一个正整数:',0
.code
main proc
lea edx,msg2
call writestring
call crlf
call readint
push eax
call print

exit
main endp

;push num
;call print
;return nothing
print proc
push ebp
mov ebp,esp
pushad

mov ebx,[ebp+8]
mov esi,31

mov eax,ebx
call writedec
mov al,'='
call writechar

again:
cmp esi,0
jl final
mov cl,1
rcl ebx,cl
mov eax,0
rcl eax,cl
cmp eax,1
jnz next
lea edx,msg1
call writestring
mov eax,esi
call writedec
cmp ebx,0
jz next
mov al,'+'
call writechar

next:
dec esi
jmp again

final:
popad
pop ebp

ret 4
print endp

end main

简单算术表达式

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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
include irvine32.inc
.data
expr db 100 dup (?)
expr1 db 20 dup (?)
expr2 db 20 dup (?)
len dd ?
ops db '+-*/',0
pos dd ?
num1 dd ?
num2 dd ?
ten dd 10
.code
main proc
lea edx,expr
mov ecx,100 ;len<128
call readstring
mov len,eax ;eax=实际读到的字符个数

push offset expr
push len
push offset ops
push offset expr1
push offset expr2
call splitexpr
mov pos,eax

push offset expr1
call trimstr
push offset expr2
call trimstr

push offset expr1
call strtoint
mov num1,eax
push offset expr2
call strtoint
mov num2,eax

push offset ops
push num1
push num2
push pos
call calculate
call writedec
call crlf

exit
main endp

;push offset expr
;push len
;push offset ops
;push offset expr1
;push offset expr2
;call splitexpr
;return eax=运算符在ops中的位置
splitexpr proc
push ebp
mov ebp,esp
sub esp,4
pushad

mov edx,0 ;edx=k
mov ebx,[ebp+16];ebx=offset ops
again:
cmp byte ptr[ebx+edx],0
jz final
;找到ops[k]在expr中的位置
mov al,byte ptr[ebx+edx]
mov edi,[ebp+24];edi=offset expr
mov ecx,[ebp+20];ecx=len
cld
repnz scasb
;从expr前部子串的第一个非空格字符开始, 将子串其余字符拷贝到expr1
cmp ecx,0
jz next
push edi
push ecx
mov eax,[ebp+20]
sub eax,ecx ;len-ecx前半部分长度
dec eax
mov ecx,eax
mov al,' '
mov edi,[ebp+24];edi=offset expr
cld
repz scasb
dec edi
inc ecx
cmp byte ptr[edi],' '
jz nul_str1
mov esi,edi
mov edi,[ebp+12]
cld
rep movsb
mov byte ptr[edi],0
;从expr后部子串的第一个非空格字符开始, 将子串其余字符拷贝到expr2
pop ecx
pop edi

mov al,' '
cld
repz scasb
dec edi
inc ecx
cmp byte ptr[edi],' '
jz nul_str2
mov esi,edi
mov edi,[ebp+8]
cld
rep movsb
mov byte ptr[edi],0
jmp final

next:
inc edx
jmp again

nul_str1:
pop ecx
pop edi
mov ebx,[ebp+12]
mov byte ptr[ebx],0

nul_str2:
mov ebx,[ebp+8]
mov byte ptr[ebx],0


final:
mov [ebp-4],edx
popad
mov eax,[ebp-4]
add esp,4
pop ebp

ret 20
splitexpr endp

;push offset expr
;call trimstr
;return nothing
trimstr proc
push ebp
mov ebp,esp
pushad

mov ebx,[ebp+8]
mov esi,0
again:
cmp byte ptr[ebx+esi],0
jz final
mov al,byte ptr[ebx+esi]
cmp al,'0'
jl badstr
cmp al,'9'
jg badstr
inc esi
jmp again

badstr:
mov byte ptr[ebx+esi],0

final:
popad
pop ebp

ret 4
trimstr endp

;push offset expr
;call strtoint
;return eax=num
strtoint proc
push ebp
mov ebp,esp
sub esp,4
pushad

mov edi,[ebp+8];edi=offset expr
dec ecx ;ecx=lengthof expr
mov esi,0
mov ebx,0 ;ebx存放结果
again:
cmp byte ptr[edi+esi],0
jz final
mov eax,ebx
mul ten
mov ebx,eax
mov dl,[edi+esi]
movzx eax,dl
sub eax,'0'
add ebx,eax
inc esi
jmp again

final:
mov [ebp-4],ebx
popad
mov eax,[ebp-4]
add esp,4
pop ebp

ret 4
strtoint endp

;push offset ops
;push num1
;push num2
;push pos
calculate proc
push ebp
mov ebp,esp
sub esp,4
pushad

mov edi,[ebp+20]
mov esi,[ebp+8]
mov cl,[edi+esi]
mov eax,[ebp+16];eax=num1
mov ebx,[ebp+12];ebx=num2

L1:
cmp cl,'+'
jnz L2
add eax,ebx
jmp final
L2:
cmp cl,'-'
jnz L3
sub eax,ebx
jmp final
L3:
cmp cl,'*'
jnz L4
mul ebx
jmp final
L4:
mov edx,0
div ebx
jmp final

final:
mov [ebp-4],eax
popad
mov eax,[ebp-4]
add esp,4
pop ebp

ret 16
calculate endp

end main

/*
step 1.输入含简单算术表达式的字符串expr
例如 " 1234 + 5678 ",0

step 2. splitExpr: 用运算符将 expr 分割为含数字
字符的俩个字符串expr1与expr2 (以0结束)
s1 : " 1234 + 5678 ",0;scasb
==> " 1234 +"
" 5678 ",0
s2 : " 1234 +" ==>
" 1234 ",0 ==>
"12 34 ",0 --->>>> expr1
" 5678 ",0==>
"5678 ",0 --->>>>expr2

int splitExpr(expr*,len,ops[],expr1*,expr2*){ops='+-/*',0
for each k in {0,1,2,3}{
若ops[k] 在expr 中,设其位置为p 则{
1.从expr前部子串的第一个非空格字符开始,
将子串其余字符拷贝到expr1
2.从expr后部子串的第一个非空格字符开始,
将子串其余字符拷贝到expr2
return k;
}
}
return 4;
}

step 3.

void trimStr( expr){
删除expr中第一个非数字字母及其后的字符;
}

step 4.
unsinged str2Int (expr){
将expr转换成无符号的整数
}
*/

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
193
194
195
include irvine32.inc
.data
msg db '729-3',0
ten dd 10
.code
main proc
;call writestring
;lea msg,edx

lea edx,msg
push offset msg
push lengthof msg
call split

mov eax,edi
call writedec
call crlf

push offset msg
push lengthof msg
push edi
call convert

mov eax,[ebx]
call writedec
call crlf
mov eax,[ecx]
call writedec
call crlf

exit
main endp

;push offset msg
;push lengthof msg
split proc
push ebp
mov ebp,esp
sub esp,4
pushad

mov ecx,[ebp+8] ;ecx=lengthof msg
mov ebx,[ebp+12]
add ebx,ecx ;ebx=msg末尾地址+2

mov edi,[ebp+12]
mov al,'+'
cld
repne scasb
jne L1

L1:
cmp edi,ebx
jnz final
mov edi,[ebp+12]
mov ecx,[ebp+8]
mov al,'-'
cld
repne scasb
jne L2

L2:
cmp edi,ebx
jnz final
mov edi,[ebp+12]
mov ecx,[ebp+8]
mov al,'*'
cld
repne scasb
jne L3

L3:
cmp edi,ebx
jnz final
mov edi,[ebp+12]
mov ecx,[ebp+8]
mov al,'/'
cld
repne scasb
jne final

final:

dec edi
mov [ebp-4],edi
popad
mov edi,[ebp-4]
add esp,4
pop ebp

ret 4
split endp

;push offset msg
;push lengthof msg
;push 符号位的地址
convert proc
push ebp
mov ebp,esp
sub esp,8
pushad

mov ebx,[ebp+16];首地址
mov edx,[ebp+16]
mov eax,[ebp+12]
add edx,eax
sub edx,2 ;末地址
;mov ecx,[esp+8] ;符号位地址

mov edi,0
mov esi,[ebp+8]
dec esi

mov eax,[ebx]
call writechar
call crlf
mov eax,[esi]
call writechar
call crlf
mov eax,[edx]
call writechar
call crlf

again1:
cmp esi,ebx
jl L2

mov eax,edi
mul ten
mov edi,eax

movzx eax,[esi]
;sub eax,
call writedecj
call crlf

add edi,eax
dec esi
jmp again1

L1:
mov [ebp-4],edi
mov edi,0
mov esi,[ebp+8]
inc esi

again2:
cmp esi,edx
jg L2
mov ecx,[esi]
sub ecx,'0'
mov eax,edi
mul ten
mov edi,eax
add edi,ecx
inc esi
jmp again2

L2:
mov [ebp-8],edi

final:
popad
mov ebx,[ebp-4]
mov ecx,[ebp-8]
add esp,8
pop ebp

ret 8
convert endp

end main
/*
void partition(int arr[],int startIndex,int endIndex,int num){
int L = startIndex - 1, R = endIndex + 1, i = startIndex;
while (i <= R - 1) {
if (arr[i] < num) {
swap(arr[i++], arr[++L]);
} else {
swap(arr[i], arr[--R]);
}
}
}

.data
alpha BYTE "ABCDEFGH",0
.code
mov edi,OFFSET alpha ;ED工指向字符串
mov al, 'F' ;检索字符F
mov ecx,LENGTHOF alpha ;设置检索计数器
cld ;方向为正向
repne seasb ;不相等则重复
jnz quit ;若未发现字符则退出
dec edi ;发现字符:EDI 减 1
*/

补充文件