Optimization 如何优化我的C/x86代码?

Optimization 如何优化我的C/x86代码?,optimization,assembly,x86,lcm,greatest-common-divisor,Optimization,Assembly,X86,Lcm,Greatest Common Divisor,我试图将顶部函数的代码与我自己的函数(底部)进行匹配。你知道我如何优化我的日常生活吗 这只是为了好玩。我会使用不同的算法进行优化。像你这样线性搜索速度非常慢。事实上,两个自然数的最小公倍数是它们的乘积除以它们的最大公因数的商。您可以使用 因此: 您需要在哪里实现gcd(int,int)。由于欧几里德算法中的平均步数是O(logn),我们轻而易举地击败了朴素的线性搜索 解决这个问题还有其他方法。如果你有一个算法,可以快速因子整数(比如a),那么你也可以这样解决这个问题。如果你把a和b中的每一个都写

我试图将顶部函数的代码与我自己的函数(底部)进行匹配。你知道我如何优化我的日常生活吗


这只是为了好玩。

我会使用不同的算法进行优化。像你这样线性搜索速度非常慢。事实上,两个自然数的最小公倍数是它们的乘积除以它们的最大公因数的商。您可以使用

因此:

您需要在哪里实现
gcd(int,int)
。由于欧几里德算法中的平均步数是
O(logn)
,我们轻而易举地击败了朴素的线性搜索

解决这个问题还有其他方法。如果你有一个算法,可以快速因子整数(比如a),那么你也可以这样解决这个问题。如果你把
a
b
中的每一个都写进它的正则素因子分解

int lcm(int a, int b) {
    int p = a * b;
    return p / gcd(a, b);
}
然后,
a
b
的最小公倍数是通过取出现在
a
b
的至少一个因子分解中的每个素因子,取出现在
a
b
的因子分解中的最大指数来获得的。例如:

a = p_a0^e_a0 * p_a1^e_a1 * ... * p_am^e_am
b = p_b0^e_b0 * p_b1^e_b1 * ... * p_bn^e_bn
所以

28 = 2^2 * 7
312 = 2^3 * 39

所有这些都是为了指出,幼稚的方法在简单性方面是令人钦佩的,但你可以花一整天的时间优化它们的最后一纳秒,但仍然无法打败一个优秀的算法。

我假设你想要保持相同的算法。这至少应该是一个稍微更有效的实现。主要区别在于循环中的代码只使用寄存器,而不使用内存

lcm(28, 312) = 2^3 * 7 * 39 = 2184
然而,正如Jason指出的,这并不是一个非常有效的算法——乘法、求GCD和除法通常会更快(除非
a
b
非常小)

编辑:还有一种算法几乎更容易理解,也应该快得多(比原来的算法——不比乘以,然后除以GCD)。不要生成连续的数字,直到找到一个同时除以
a
b
,而是生成一个的连续倍数(最好是较大的倍数),直到找到一个均匀除以另一个:

int lcm(int a,int b)  {
    __asm {
        xor ecx, ecx
        mov esi, a
        mov edi, b
lstart:
        inc ecx
        mov eax, ecx
        xor edx, edx
        idiv esi
        test edx, edx
        jne lstart
        mov eax, ecx;
        idiv edi
        test edx, edx
        jnz lstart
        mov eax, ecx
        leave
        ret
    }
}

这仍然很容易理解,但应该比原始版本有相当大的改进。

@chris:编译器产生更好的汇编是一个神话。人类将永远获胜,特别是对于特殊的小功能。当然,他们需要更长的时间来创建它。@reinier:根据具体情况,人们可以将“创建它需要更长的时间”等同于“非常、非常不可能”。@raphael:我的意思是“需要更长的时间”:如果我点击“编译”按钮,编译器会在眨眼之间创建并优化成吨的代码。要手动为一个例程创建手动优化的程序集,可能需要几分钟甚至几个小时。但是,在某些情况下,这是值得的,如果每个周期都很重要,并且函数被大量使用(在游戏开发中,这种情况经常发生)@Raphalsp:如果你说不太可能有人会费心手动优化大多数例程,那么你是绝对正确的。如果你说一个人不太可能在大多数例程中产生比编译器更好的代码,那么你就大错特错了。@reinier和@jerry:显然,我指的是jerry的#1。这在游戏开发中经常发生吗?我相信你的话。在高性能图像处理中?我就拿我的来说:我们已经改用了编译器内部函数,很少后悔。谢谢你的PS。这样,我们就不必给你上微优化课了,这让每个人都很开心。
int lcm(int a,int b)  {
    __asm {
        xor ecx, ecx
        mov esi, a
        mov edi, b
lstart:
        inc ecx
        mov eax, ecx
        xor edx, edx
        idiv esi
        test edx, edx
        jne lstart
        mov eax, ecx;
        idiv edi
        test edx, edx
        jnz lstart
        mov eax, ecx
        leave
        ret
    }
}
int lcm2(int a, int b) { 
    __asm { 
        xor ecx, ecx
        mov esi, a
        mov edi, b
    lstart:
        add ecx, esi
        mov eax, ecx
        xor edx, edx
        idiv edi
        test edx, edx
        jnz lstart
        mov eax, ecx
        leave
        ret
    }
}