Assembly 有人知道如何使用汇编x86语言将N个奇数相加吗?
有人知道如何使用汇编x86语言和MUL助记符来计算N个奇数吗Assembly 有人知道如何使用汇编x86语言将N个奇数相加吗?,assembly,x86,Assembly,X86,有人知道如何使用汇编x86语言和MUL助记符来计算N个奇数吗 例如:SUM=1*3*5*7*………*n要使用MUL指令相乘,您将一个数字放入eax(或rax或ax,具体取决于操作数大小)和另一个数字(在任何其他寄存器或内存中),然后执行MUL,并在edx:eax(或rdx:rax或dx:ax) 例如(32位,NASM语法,未测试): 当然,当它们是常量时,您可以欺骗它们,并让汇编程序在汇编代码时这样做。例如(32位,NASM语法,未测试): 您还可以在循环中执行MUL。例如,如果值来自表或数组(
例如:SUM=1*3*5*7*………*n要使用
MUL
指令相乘,您将一个数字放入eax
(或rax
或ax
,具体取决于操作数大小)和另一个数字(在任何其他寄存器或内存中),然后执行MUL
,并在edx:eax
(或rdx:rax
或dx:ax
)
例如(32位,NASM语法,未测试):
当然,当它们是常量时,您可以欺骗它们,并让汇编程序在汇编代码时这样做。例如(32位,NASM语法,未测试):
您还可以在循环中执行MUL
。例如,如果值来自表或数组(32位,NASM语法,未测试):
但是,如果这些值之间存在某种关系,则不需要表格。我认为您的顺序似乎错误,我怀疑您实际上想要“1*3*5*7…N
”(并且怀疑2
是一个打字错误),“1*3*5*7…N
”是一个可以在没有表格的情况下完成的顺序。例如(32位,NASM语法,未测试):
请注意,您可以通过欺骗来提高性能。例如,您可以这样做(32位,NASM语法,未经测试):
使用预先计算的查找表可以欺骗更多的人。例如(32位,NASM语法,未测试):
当然,您可以像这样将表的大小减半:
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语法,未测试):
欢迎使用堆栈溢出。请阅读,特别是和。最后学习如何创建。查找任何阶乘循环,并将其更改为递增2而不是1。为什么要使用一个操作数
mul ecx
,而不是像imul eax,ecx
这样至少稍微更有效的操作数()?您希望扩展精度的结果比寄存器更宽吗?顺便说一句,mul
不是“关键字”,这是一个指令助记符。是的,我的问题中有一个输入错误,但它已经被编辑。英语不是我的第一语言,我以前从未使用过stackoverflow,这是我第一次。我不使用IMUL的原因是因为我只知道一些助记符,如mov、add、sub和mul。奇怪的是,你没有提到一个操作数mul
(Haswell上的3个uop)的效率低于imul eax、ebx(基本上所有设备上的1个uop)…使用mul
是一种完全人为的约束,它会使代码变慢,并且只有在您真正想要高一半的结果时才有用。此外,使用两个累加器可以让您并行运行两个依赖关系链,分别执行1*5*9*13*.
和3*7*11*15*.
,并在最后将两者相乘。因为>imul
至少有3个周期延迟,这将使大n
的吞吐量翻倍(由于我们避免偶数,大n
不仅会导致低32位都为零。因此模块化结果可能很有趣。)你的记忆/缓存方法很有趣,但你坚持在ebx
中保留索引,这会使代码复杂化。如果你改为在ebx中保留idx*2+1
(即你想乘以的东西),那么你就可以使用addebx,2
/imul eax,ebx
/mov[resultable+ebx*2-2],eax
。您可以使用EDX而不是EBX。这里也没有理由使用lea
而不是add
;在Intel CPU上,您只是在整数乘法单元所在的端口1上产生了更多资源冲突的可能性。也许如果您正在为顺序原子进行调优?@PeterCordes:实际上;对于32位,这是可能的对于N>=13
,y将溢出,如果它只适用于较小的N
,则预计算的表(例如,可能不超过7个条目?)将比有代码的表更小、更容易。同样适用于64位(仅适用于N@PeterCordes:Heh-示例代码是示例代码)(除了说明一个概念之外,没有其他理由存在,没有真正的理由对其进行优化,也没有真正的理由关心它是否正确或充满bug)。
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
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
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
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:
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: