根据条件然后三元运算符获得值的更快方法?

时间:2016-11-18 08:52:45

标签: c++ c optimization

这是我试图实现的目标。这很简单:

unsigned int foo1(bool cond, unsigned int num)
{
    return cond ? num : 0;
}

Assmebly:

    test    dil, dil
    mov     eax, 0
    cmovne  eax, esi
    ret

我的问题是,有更快的方法吗?以下是我想到的一些方法:

使用乘法:

unsigned int foo2(bool cond, unsigned int num)
{
    return cond * num;
}

ASSMBLY:

    movzx   eax, dil
    imul    eax, esi
    ret

使用内存访问:

unsigned int foo3(bool cond, unsigned int num)
{
    static const unsigned int masks[2] = { 0x0, 0xFFFFFFFF };
    return masks[cond] & num;
}

大会:

    movzx   edi, dil
    mov     eax, DWORD PTR foo3(bool, unsigned int)::masks[0+rdi*4]
    and     eax, esi
    ret

使用一些技巧:

unsigned int foo4(bool cond, unsigned int num) 
{
    return (0 - (unsigned)cond) & num;
}

大会:

    movzx   eax, dil
    neg     eax
    and     eax, esi
    ret

现在,乘法产生最少的指令,我认为它是最好的选择,但我不确定imul。有什么建议吗?

提前致谢,

3 个答案:

答案 0 :(得分:1)

乘法和内存访问比简单的if语句花费更多时间。如果您想优化此代码,最好的方法是仅使用"和"或"或"指令(将其设置为内联以避免函数调用)。

这是一个优化的'使用蒙版而不是布尔值的函数示例:

inline unsigned int foo1(unsigned int mask, unsigned int num)
{
  return mask & num;
}

您的电话将如下所示:

foo1(0, 10);     /* Returns 0  */
foo1(~0, 10);    /* Returns 10 */

答案 1 :(得分:1)

优化代码并不总是像计算汇编程序指令和CPU标记一样简单。

乘法方法在大多数系统上可能是最快的,因为它删除了一个分支。在大多数CPU内核上,乘法指令应该相当快。

你可以考虑的是,如果你真的需要使用这么大的整数类型。在小型8位或16位CPU上,以下代码会明显加快:

uint_fast16_t foo2(bool cond, uint_fast16_t num)
{
    return (uint_fast16_t)cond * num;
}

另一方面,这些CPU很少带有分支预测或指令缓存。

您不必担心手动功能内联。编译器将在大多数编译器上自动内联此函数。

答案 2 :(得分:0)

观看所有精彩的答案和评论,

我认为这是正确答案:

当达到微观优化水平时,没有“最佳”选择,因为它可能因平台,操作系统和书面软件而异。

因此,在我看来,软件方面的正确方法是创建多个实现,并使用一些抽象封装它们,以便可以轻松切换。

在进行基准测试时,在它们之间切换以查看哪一个产生了最佳的情况。

当然,我们可以排除明显比其他解决方案更差的解决方案。