有人知道如何使用使用MUL助记符的Assembly x86语言对N个奇数进行倍数运算 例如:SUM = 1 * 3 * 5 * 7 * .......... * n
答案 0 :(得分:1)
要将数字与MUL
指令相乘,您可以将一个数字放在eax
(或rax
或ax
中,具体取决于操作数的大小),另一个数字放在其他位置(在任何位置其他寄存器或内存中),然后执行MUL
并期望结果在edx:eax
(或rdx:rax
或dx:ax
中)。
例如(32位,NASM语法,未经测试):
mov eax,1 ;eax = 1
mov ebx,2 ;ebx = 2
mov ecx,5 ;ecx = 5
mul ebx ;edx:eax = 1 * 2
mul ecx ;edx:eax = (1 * 2) * 5
当然,当它们为常量时,您可以作弊,并在汇编代码时让汇编器执行。例如(32位,NASM语法,未经测试):
mov eax,1*2*5*7
您还可以循环执行MUL
。例如,如果值来自表或数组(32位,NASM语法,未经测试):
mov eax,[table]
mov esi,table+4
mov ecx,31-1 ;31 items in table?
.next:
mul dword [esi] ;edx:eax = temp * table[i]
add esi,4
loop .next
但是,如果值之间存在某种关系,则不需要表。您的序列对我来说似乎是错误的,我怀疑您实际上是想使用“ 1*3*5*7 ... N
”(并怀疑2
是一个错字),而“ 1*3*5*7 ... N
”是一个序列,可以不用一张桌子。例如(32位,NASM语法,未经测试):
mov ecx,31 ;ecx = N = 31
mov ebx,1 ;ebx = the value the result was multiplied with last
mov eax,1 ;eax = the result
.next:
lea ebx,[ebx+2] ;ebx = the value to multiply with the result next
mul ebx ;edx:eax = new current result
cmp ebx,ecx ;Has N been reached?
jb .next ; no, keep going
请注意,您可以作弊以提高性能。例如,您可以执行以下操作(32位,NASM语法,未经测试):
mov ecx,31 ;ecx = N = 31
mov eax,1 ;eax = the current result
mov ebx,1 ;ebx = the value the result was multiplied with last
cmp ecx,9 ;Is the last value greater than 9?
jle .next ; no, don't cheat
mov eax,1*3*5*7*9 ; yes, cheat by skipping the first 4 multiplications
mov ebx,9
.next:
lea ebx,[ebx+2] ;ebx = the value to multiply with the result next
mul ebx ;edx:eax = new current result
cmp ebx,ecx ;Has N been reached?
jb .next ; no, keep going
您可以使用预先计算的查找表进行更多欺骗。例如(32位,NASM语法,未经测试):
mov ecx,31 ;ecx = N = 31
mov eax,[resultTable + ecx*4] ;eax = result for N
您当然可以将表格的大小减半:
mov ecx,31 ;ecx = N = 31
shr ecx,1 ;ecx = N/2 = 15
mov eax,[resultTable + ecx*4] ;eax = result for N
您还可以在运行时构建表,将其有效地转变为一种缓存:
mov ecx,31 ;ecx = N = 31
mov edx,ecx ;edx = N
shr edx,1 ;edx = N/2
cmp dword [resultTable + edx*4],0 ;Is the result for this N already known?
je .unknown ; no, have to calculate it
mov eax,[resultTable + edx*4] ; yes, just use the result from last time
jmp .done
.unknown:
mov eax,1 ;eax = the current result
mov ebx,1 ;ebx = the value the result was multiplied with last
cmp ecx,9 ;Is the last value greater than 9?
jle .next ; no, don't cheat
mov eax,1*3*5*7*9 ; yes, cheat by skipping the first 4 multiplications
mov ebx,9
.next:
lea ebx,[ebx+2] ;ebx = the value to multiply with the result next
mul ebx ;edx:eax = new current result
cmp ebx,ecx ;Has N been reached?
jb .next ; no, keep going
shr ecx,1 ;ecx = N/2
mov [resultTable + edx*4],eax ;Store the result for next time
.done:
但是,任何先前较低值N
的结果都可以用作计算N
较高值的结果的起点。这导致以下方法(32位,NASM语法,未经测试):
mov ecx,31 ;ecx = N = 31
shr ecx,1 ;ecx = N/2
mov ebx,[highestN2] ;ebx = the highest N/2 that's been done before
cmp ecx,ebx ;Has this N/2 been done before?
ja .unknown ; no
mov eax,[resultTable + ecx*4] ; yes, use the previously calculated result
jmp .done
.unknown:
mov eax,[resultTable + ebx*4] ;eax = highest result previously calculated
.next:
inc ebx ;ebx = next N/2 to use
lea edx,[ebx*2+1] ;edx = next N to use
mul edx ;edx:eax = old result * N
mov [resultTable + ebx*4],eax ;Store it for later
cmp ebx,ecx ;Have we done enough?
jb .next ; no, keep going
mov [highestN2],ebx ;Set the new highest N/2 calculated so far
.done: