查找两个之间的最大数,选择哪个实现

我想弄清楚,在找到两个之间的最大数量时,哪个实现比其他实现更具优势。作为一个例子,让我们检查两个实现:

实施1:

int findMax (int a, int b)
{
    return (a > b) ? a : b; 
}

// 汇编输出:(gcc 11.1)

    push    rbp
    mov     rbp, rsp
    mov     DWORD PTR [rbp-4], edi
    mov     DWORD PTR [rbp-8], esi
    mov     eax, DWORD PTR [rbp-4]
    cmp     eax, DWORD PTR [rbp-8]
    jle     .L2
    mov     eax, DWORD PTR [rbp-4]
    jmp     .L4 .L2:
    mov     eax, DWORD PTR [rbp-8] .L4:
    pop     rbp
    ret

实施2:

int findMax(int a, int b)
{
    int diff, s, max;
    diff = a - b;
    s = (diff >> 31) & 1;
  
    max = a - (s * diff);
  
    return max;
}

// 汇编输出:(gcc 11.1)

    push    rbp
    mov     rbp, rsp
    mov     DWORD PTR [rbp-20], edi
    mov     DWORD PTR [rbp-24], esi
    mov     eax, DWORD PTR [rbp-20]
    sub     eax, DWORD PTR [rbp-24]
    mov     DWORD PTR [rbp-4], eax
    mov     eax, DWORD PTR [rbp-4]
    shr     eax, 31
    mov     DWORD PTR [rbp-8], eax
    mov     eax, DWORD PTR [rbp-8]
    imul    eax, DWORD PTR [rbp-4]
    mov     edx, eax
    mov     eax, DWORD PTR [rbp-20]
    sub     eax, edx
    mov     DWORD PTR [rbp-12], eax
    mov     eax, DWORD PTR [rbp-12]
    pop     rbp
    ret

第二个产生了更多的汇编指令,但第一个有条件跳转。只是想了解两者是否同样好。

回答

首先,您需要打开编译器优化(我用于-O2以下内容)。你应该比较std::max. 然后这个:

#include <algorithm>

int findMax (int a, int b)
{
    return (a > b) ? a : b; 
}

int findMax2(int a, int b)
{
    int diff, s, max;
    diff = a - b;
    s = (diff >> 31) & 1;
  
    max = a - (s * diff);
  
    return max;
}

int findMax3(int a,int b){
    return std::max(a,b);
}

结果:

findMax(int, int):
        cmp     edi, esi
        mov     eax, esi
        cmovge  eax, edi
        ret
findMax2(int, int):
        mov     ecx, edi
        mov     eax, edi
        sub     ecx, esi
        mov     edx, ecx
        shr     edx, 31
        imul    edx, ecx
        sub     eax, edx
        ret
findMax3(int, int):
        cmp     edi, esi
        mov     eax, esi
        cmovge  eax, edi
        ret

您的第一个版本产生与 相同的程序集std::max,而您的第二个变体则做得更多。实际上,在尝试优化时,您需要指定优化的对象。有几个选项通常需要进行权衡:运行时、内存使用、可执行文件的大小、代码的可读性等。通常您无法一次获得所有这些。

如有疑问,请不要重新发明轮子,而是使用现有的已经优化的std::max. 并且不要忘记,您编写的代码不是针对 CPU 的指令,而是对程序应该做什么的高级抽象描述。编译器的工作是弄清楚如何最好地实现这一目标。

最后但并非最不重要的是,您的第二个变体实际上已损坏。请参阅此处编译的示例-O2 -fsanitize=signed-integer-overflow,结果为:

/app/example.cpp:13:10: runtime error: signed integer overflow: -2147483648 - 2147483647 cannot be represented in type 'int'

你应该赞成正确而不是速度。最快的代码在出错时一文不值。正因为如此,可读性是列表中的下一个。难以阅读和理解的代码也难以证明是正确的。在编译器的帮助下,我只能在您的代码中发现问题,而std::max(a,b)不太可能导致未定义的行为(即使确实如此,至少这不是您的错;)。


以上是查找两个之间的最大数,选择哪个实现的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>