7

这是:

int val;  
// ...
val = (val != 0) ? otherVal : 0;

效率低于此:

int val;
//...
if (val != 0)
    val = otherVal;

?

编译器是否能够优化三元运算符?意图很明确,有什么办法可以将 0 实际写入内存?也许当内存映射到文件时?

我们可以假设它不重要吗?

编辑:关键是如果满足一个条件,则将变量设置为某个值。没有想要的 else 分支。这就是为什么我问一个三元组(具有应该复制的强制性 else 分支)是否会降低效率或优化。

4

5 回答 5

5

Mats Petersson 的建议通常是最好的“编写最易读的变体”。但是,如果您尝试编写最佳速度性能代码,则需要了解有关您的计算机和处理器的更多信息。对于某些机器,第一个将运行得更快(高度流水线处理器:无分支,优化的三元运算符)。使用第二种形式(更简单),其他机器将运行得更快。

于 2013-05-22T16:30:55.683 回答
4

你的编译器会优化它。最后,性能几乎没有差异。

但是,可读性存在很大差异。有时,三元运算符可以帮助删除许多不会增加清晰度的代码行。

在其他情况下,该if声明更清晰,更易于理解。

将代码简化为三元语句,然后必须添加大量注释以保持清晰性会适得其反。

并且所有的编码之神,请不要嵌套三元语句。

于 2013-05-22T16:26:39.417 回答
4

您可以使用无分支三元运算符,有时称为位选择(条件?真:假)。

不要担心额外的操作,与 if 语句分支相比,它们微不足道。

位选择实现:

inline static int bitselect(int condition, int truereturnvalue, int falsereturnvalue)
{
    return (truereturnvalue & -condition) | (falsereturnvalue & ~(-condition)); //a when TRUE and b when FALSE
}

inline static float bitselect(int condition, float truereturnvalue, float falsereturnvalue)
{
    //Reinterpret floats. Would work because it's just a bit select, no matter the actual value
    int& at = reinterpret_cast<int&>(truereturnvalue);
    int& af = reinterpret_cast<int&>(falsereturnvalue);
    int res = (at & -condition) | (af & ~(-condition)); //a when TRUE and b when FALSE
    return  reinterpret_cast<float&>(res);
}
于 2015-05-06T18:06:48.227 回答
2

这主要是三元运算符的副本 ?: vs if...else

对于大多数编译器,效率是相同的,编译器将优化三元运算符,就像优化 if/else 语句一样。也就是说,我更喜欢 if 语句,因为它们使代码更容易一目了然地阅读。

回答您的其他问题。我不确定您的意思,如果您只是将一个整数或变量设置为 0,那么除了像上面那样将其设置为零之外没有更快的方法。

如果你有一个变量数组,你可以使用memset(ptr, 0, size*sizeof(TYPE)),如果你有一个变量数组你想设置为零,这可能是最快的。或者可能是 std::fill_n

我不确定你想用上面的逻辑实现什么,但这似乎有点奇怪。有一些方法可以安排代码,这意味着您可能根本不需要条件,但是如果没有看到更多代码,很难说出您的情况。

老实说,除非您执行此操作数十亿次,否则这可能是非常不成熟的优化,您应该专注于可读性。

于 2013-05-22T16:27:15.347 回答
0

“编译器资源管理器”之类的工具非常适合回答此类问题。修复代码中的错误并比较以下两个片段,我们看到它们在 -O1 和更高版本中生成相同的程序集。

void trinary(int& val, int otherVal) {
    val = (val != 0) ? otherVal : 0;
}

void nontrinary(int& val, int otherVal) {
    if(val != 0) {
        val = otherVal;
    }
    else {
        val = 0;
    }
}

trinary(int&, int):
        mov     eax, DWORD PTR [rdi]
        test    eax, eax
        mov     eax, 0
        cmove   esi, eax
        mov     DWORD PTR [rdi], esi
        ret
nontrinary(int&, int):
        mov     eax, DWORD PTR [rdi]
        test    eax, eax
        mov     eax, 0
        cmove   esi, eax
        mov     DWORD PTR [rdi], esi
        ret

有趣的是,在 -O0 处,它们不会产生相同的输出。在 -O0 处,编译器用于eax显式存储三元运算符的结果,然后eax在返回之前复制到正确的寄存器中。非三元版本直接进行赋值。

trinary(int&, int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        test    eax, eax
        je      .L2
        mov     eax, DWORD PTR [rbp-12]
        jmp     .L3
.L2:
        mov     eax, 0
.L3:
        mov     rdx, QWORD PTR [rbp-8]
        mov     DWORD PTR [rdx], eax
        nop
        pop     rbp
        ret
nontrinary(int&, int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        test    eax, eax
        je      .L5
        mov     rax, QWORD PTR [rbp-8]
        mov     edx, DWORD PTR [rbp-12]
        mov     DWORD PTR [rax], edx
        jmp     .L7
.L5:
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax], 0
.L7:
        nop
        pop     rbp
        ret
于 2019-10-31T17:46:17.197 回答