这是:
int val;
// ...
val = (val != 0) ? otherVal : 0;
效率低于此:
int val;
//...
if (val != 0)
val = otherVal;
编译器是否能够优化三元运算符?意图很明确,有没有什么方法可以实际写0到内存?也许当内存映射到文件?
我们可以假设没关系吗?
编辑:关键是如果满足一个条件,则将变量设置为某个值。没有其他想要的分支。这就是为什么我问三元(带有强制性的其他分支应该制作副本)是否会降低效率或优化。
答案 0 :(得分:4)
您的编译器将对其进行优化。最后,表现几乎没有差别。
然而,可读性存在很大差异。有时,三元运算符可以帮助删除许多代码,这些代码不会在清晰度上添加很多。
在其他情况下,if
声明更清晰,更容易理解。
将代码缩减为三元语句,但为了保持清晰度而必须添加大量注释会适得其反。
所有编码之神,请不要嵌套三元语句。
答案 1 :(得分:4)
Mats Petersson的建议通常是最好的“编写最易读的变体”。 但是,如果您正在尝试编写最佳速度性能代码,则需要了解有关计算机和处理器的更多信息。对于某些机器,第一台将运行得更快(高度流水线处理器:没有分支,优化的三元运算符)。其他机器将以第二种形式运行得更快(更简单)。
答案 2 :(得分:3)
您可以使用无分支三元运算符,有时也称为bitselect(条件?true:false)。
不要担心额外的操作,与if语句分支相比,它们无关紧要。
bitselect implementation:
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);
}
答案 3 :(得分:2)
这主要是Ternary operator ?: vs if...else
的副本对于大多数编译器而言,效率将是相同的,编译器将优化三元运算符,就像它优化if / else语句一样。也就是说,我更喜欢if语句,因为它们使代码更容易阅读。
回答您的其他问题。我不确定你的意思,如果你只是将一个整数或变量设置为0,那么除了像上面那样将它设置为零之外没有更快的方法。
如果你有一个变量数组,你可以使用memset(ptr, 0, size*sizeof(TYPE))
,如果你想要设置为零的变量数组,这可能是最快的。或者也许是std :: fill_n
我不确定你用上述逻辑尝试实现的目标,但似乎有点奇怪。有一些方法可以安排代码,这意味着你可能根本不需要条件,但是如果没有看到更多的代码,很难说出你的情况。
说实话,除非你做了数十亿次这样的操作,否则这可能是非常成熟的优化,你应该专注于可读性。
答案 4 :(得分:0)
诸如“编译器资源管理器”之类的工具非常擅长回答此类问题。修复了代码和comparing the following two snippets中的错误后,我们看到它们在-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