这是我的任务。 我已经为这个程序集完成了我的代码,但有没有办法让转换速度更快? 感谢任何帮助; D
//Convert this nested for loop to assembly instructions
for (a = 0; a < y; a++)
for (b = 0; b < y; b++)
for (c = 0; c < y; c++)
if ((a + 2 * b - 8 * c) == y)
count++;
convert
_asm {
mov ecx,0
mov ax, 0
mov bx, 0
mov cx, 0
Back:
push cx
push bx
push ax
add bx, bx
mov dx, 8
mul dx
add cx, bx
sub cx, ax
pop ax
pop bx
cmp cx, y
jne increase
inc count
increase : pop cx
inc ax
cmp ax, y
jl Back
inc bx
mov ax, 0
cmp bx, y
jl Back
inc cx
mov ax, 0
mov bx, 0
cmp cx, y
jl Back
}
答案 0 :(得分:4)
一些通用技巧:
LEA
计算表达式的神奇之处,这些表达式包含2个特定幂的加法和缩放。在任何地方都不需要MUL
。 a + 2*b
对于c循环的每次迭代都是常量。 SI
,DI
来保存值。这应该可以帮助您避免所有push
和pop
指令。AH
,AL
等来更有效地使用您的寄存器。哦,mov ax, 0
之后您不需要inc cx
,因为AX
已经为0了。
特定于此算法:如果y
为奇数,则跳过a
为偶数的迭代,反之亦然。将近2倍的加速等待......(如果你想知道为什么,请用铅笔和纸做。)提示:你也不需要测试每次迭代。如果你足够聪明的话,你可以简单地逐步走2点。
或者更好的是,制作一个封闭的表格,让您直接计算答案。 ; - )
答案 1 :(得分:3)
当你进行优化时,总是从高处开始变低,即从算法级别开始,当一切都用尽时,进入程序集转换。
首先,请注意:
8 * c = (a + 2 * b - y)
每个三联体(a,b,y)都有一个独特的c解决方案。
这是什么意思?你的3个循环可以折叠成2个。这是从运行时到y ^ 3到the y y ^ 2的巨大减少。
重写代码:
for (a = 0; a < y; a++)
for (b = 0; b < y; b++) {
c = (a+2*b-y);
if (((c%8)==0) && (c >= 0)) count++;
}
接下来观察c> = 0表示:
a+2*b-y >= 0
a+2*b >= y
a >= y-2b
请注意,两个循环可以互换,这给出了:
for (b = 0; b < y; b++) {
for (a = max(y-2*b,0); a < y; a++) {
if (((a+2*b-y)%8)==0) count++;
} }
我们可以分成两部分:
for (b = 0; b < y/2; b++) {
for (a = y-2*b; a < y; a++) {
if (((a+2*b-y)%8)==0) count++;
} }
for (b = y/2; b < y; b++) {
for (a = 0; a < y; a++) {
if (((a+2*b-y)%8)==0) count++;
} }
现在我们完全取消了c。我们不能在没有提出封闭式公式(或至少部分封闭式公式)的情况下完全消除a或b,为什么?
所以这里有几个练习可以帮助你,#34;。&#34;。
现在转换为汇编语言会给你一个很大的改进:p
(我希望所有细节都是正确的。如果你发现错误,请更正)
答案 2 :(得分:0)
在Assembly Language Step-by-Step杰夫在第230页写道,
现在,速度优化在x86世界中是一个非常滑动的业务,在CPU缓存中指令而不是从内存中拉出它们是一个速度差异,它淹没了指令本身之间的大多数速度差异。其他因素在最新的Pentium级CPU中发挥作用,这些CPU几乎不可能对指令速度进行概括,并且当然不可能以任何精度进行说明。
假设您使用的是x86计算机,我的建议就是尽可能地吸收所有Math中的数学,以便为优化提供最好的答案。