为什么按位运算符不像逻辑“和\或”运算符那样智能

时间:2014-05-13 14:49:58

标签: c# optimization operators bit-manipulation

我只是注意到按位操作不是" smart"作为逻辑"和\或"操作,我想知道为什么?

以下是一个例子:

// For the record
private bool getTrue(){return true;}
private bool getFalse(){return false;}

// Since a is true it wont enter getFalse.
bool a = getTrue() || getFalse(); 

// Since a is false it wont enter getTrue.
bool b = getFalse() && getTrue(); 

// Since b is false it wont enter getTrue.
b = b && getTrue();

然而,按位运算符" | ="和"& ="并不聪明:

bool a = getTrue();
a |= getFalse(); // a has no chance to get false but it still enters the function.

a = getFalse();
a &= getTrue(); // a has no chance to get true but still performs this operation.

我想知道为什么他们不能以同样的逻辑方式工作。

3 个答案:

答案 0 :(得分:10)

一个澄清:

&=上进行求值时,运算符|=bool不是按位运算符 - 它们是逻辑运算符,但它们相当于x = x & y和{{1 }},它不像x = x | y&&那样短路。

来自MSDN

  

&运算符对积分操作数和bool操作数上的逻辑AND执行按位逻辑AND运算。

设计师可以实施||||=,但由于适用于布尔类型,因此那里没什么价值。

答案 1 :(得分:8)

D Stanley's answer是正确的;您的错误是在&应用于bool时将其视为“按位”。在应用于&时,最好将&&bool视为逻辑AND的渴望和懒惰版本。

现在这是一个你没有问的问题,但实际上是一个更有趣的问题:

  

为什么首先存在bool的AND和OR的非短路版本?也就是说,为什么你会说exprX & exprY而不是exprX && exprY

错误的原因是:无论exprY的值如何,表达式exprX都可能会产生副作用。这是一个不好的理由,因为将表达式用于其副作用及其值是一个值得怀疑的做法。

很好的理由是:计算&&&更快。

怎么可能?当然,如果我们可以在某些时候避免计算右侧,那么我们可以始终平均节省时间,对吗?

错误的错误。 z = x && y将生成为具有以下结构的代码:

if x goto CONSEQUENCE
z = false
goto DONE
CONSEQUENCE: z = y
DONE: 

与简单地计算x & y并将结果分配给z相比,这是很多指令,大型代码需要更多时间来加载磁盘,更多时间进行jit编译,并占用更多空间在处理器缓存中。

此外,这些指令包含条件分支和非条件分支,大大增加了抖动必须处理的基本块的数量。 (“基本块”是一段具有明确开始和结束的代码,如果没有异常,基本块中的所有代码都会执行。)当基本块的数量时,抖动可能会选择避开某些优化必须分析得太大。

最糟糕的是,任何条件分支都会让CPU有机会让其分支预测器做出错误的选择,这在某些情况下可能会产生严重的性能影响。

现在,这并不是说你永远不应该使用&&作为bools;目前还没有程序在市场上取得的巨大成功归功于这种纳米优化的使用。我只是因为并不完全明白为什么在bool上应该有一个非短路的逻辑运算符,这一点。

答案 2 :(得分:2)

主要区别在于您是否使用| / &|| / &&。后者的短路(你称之为" smart"),而前者则没有(这是处理布尔类型时运算符之间的唯一区别)。由于没有&&=||=运营商,您只会注意到&=|=,正如符号所示,它们不会短路。

我认为&=|=可能存在但&&=||=不存在,因为前者'在数字类型中使用,其中短路是没有意义的。