基于布尔值的C评估 - 哪个更快,哪个风格更好?

时间:2016-10-21 15:45:55

标签: c boolean-expression

似乎一般来说,在C(以及许多其他语言)中,人们也可以这样做,例如:

if (x > 0){
    y = value1;
}
else{
    y = value2;
}

y = (x>0)*value1 + (x <= 0)*value2;

第一种情况在风格上似乎更好,因为它更容易阅读(对大多数人来说?)。但是,第二种情况再次紧凑。更重要的是,性能有何不同?似乎第二种情况可能更慢,因为两个布尔表达式都被计算,并且有一个乘以零..但是,我隐约回想起如果语句有一些小的额外开销?我意识到我实际上可以衡量速度,但希望有人有一个更一般的答案。

3 个答案:

答案 0 :(得分:2)

y = (x>0)*value1 + (x <= 0)*value2;

这是可怕的代码,不应该写(你需要100%确定比较运算符返回1为“true”;是否是这样的情况需要很多东西)。

这就是C语言中三元运算符的用途:

 y = (x > 0) ? value1 : value2;
  

更重要的是,性能有何不同?

我很想就“重要性”发表争论,但是:

没有。如果编译器值得,则三元运算符应扩展为与if构造相同的字节码。你的y=(cond)*a+(!cond)*b构造更可能变慢,因为乘法的奇怪滥用;但是,无论如何,现代的优化编译器可能会杀死它。

答案 1 :(得分:1)

使用if所涉及的性能损失是由于它涉及分支。然而,像(x> 0)这样的表达式最可能也涉及分支。另外,正如您所提到的,在您的单个表达式中,您正在评估两个不同的条件,而在if中,您只评估一个条件。正如其他人所提到的,编译器可能会将单个表达式和if优化为相同的代码。最终,if要好得多,因为它清楚它正在做什么。正如@Ed所提到的,如果要优化性能,请进行性能分析。然后,您可以专注于代码中花费最多时间的部分。

答案 2 :(得分:1)

正确性的第一个代码,然后为了清楚起见(当然,这两个经常连接!)。最后,只有你有真正需要的实证证据,你才能看到优化。过早的优化确实是邪恶的。优化几乎总是花费您的时间,清晰度和可维护性。你最好确定你买了一些有价值的东西。

y = (x>0)*value1 + (x <= 0)*value2;

不要在任何代码中使用它。这是关于如何编写terrible代码的一个很好的例子,因为它根本不直观。此外,您是否会获得任何性能提升取决于您的计算机体系结构(取决于您的体系结构的multiplication instruction所采用的周期数)。

然而,C和C ++中的条件语句(例如if else),在最低级别(在硬件中),是昂贵的。为了理解原因,您必须了解pipelines的工作原理。它可能导致管道冲洗并降低处理器的效率。

Linux kernel使用条件语句的优化技术,它是__builtin_expect。使用条件语句(if-else语句)时,我们经常知道哪个分支是真的,哪个分支不是(最可能的)。如果编译器事先知道这些信息,它可以生成最优化的代码。

#define likely(x)      __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)

if (likely(x > 0)) {
    y = value1;
} else {
    y = value2;
}

对于上面的示例,我将if条件标记为likely()为true,因此编译器将在分支后立即放置真实代码,并在分支指令内放置假代码。这样编译器就可以实现优化。但是不要盲目使用likely()unlikely()宏。如果预测是正确的,则意味着跳转指令的周期为零,但如果预测错误,那么将需要几个周期,因为处理器需要刷新它的管道,这比没有预测更糟糕。