MonoDevelop建议将if语句转换为按位运算

时间:2015-03-26 13:33:37

标签: c# monodevelop bitwise-operators boolean-logic

MonoDevelop建议转向:

if (someBoolVar)
    anotherBoolVar = true;

进入这个:

anotherBoolVar |= someBoolVar;

当我将anotherBoolVar设置为false时,它也会这样做:

if (someBoolVar)
    anotherBoolVar = false;

变为:

anotherBoolVar &= !someBoolVar;

有人可以解释这些陈述是否相同吗?

6 个答案:

答案 0 :(得分:12)

嗯,在功能上他们是等同的。

在第一种情况下,如果anotherBoolVartrue,您希望将someBoolVar设置为true,无论anotherBoolVar当前具有什么值,替换表达式那样做。

这是短暂的:

anotherBoolVar = anotherBoolVar | someBoolVar;

第二个替换也与它替换的代码相同,并且简称:

anotherBoolVar = anotherBoolVar & (!someBoolVar);

解决方案隐藏在"按位"在这种情况下,布尔变量的性质。使用反转值(~反转someBoolVar将有效地说"保留!someBoolVar中设置的所有位并清除rest",意思是如果someBoolVar为真,则会将其反转为false,并且您将有效地清除anotherBoolVar


现在,你应该这样做吗?

在我看来,没有。代码更具可读性。保持,甚至可能寻找一种方法让MonoDevelop在将来不再提出这些建议。

答案 1 :(得分:3)

IDE代码建议通常是双刃剑。是的,这些陈述更为严厉,但它们也可能令人困惑(因此你在思考)。

if (someBoolVar)
    anotherBoolVar = someBoolVar;

相同
anotherBoolVar |= someBoolVar;

因为如果someBoolVar为false,|=会短路。如果someBoolVar为true,则它不会短路,因此将someBoolVar值(true)分配给anotherBoolVar。

虽然可以略微优化更简洁的陈述,但我建议您坚持使用if语句,因为它更具表现力和可读性。

对于这些类型的if语句,我尝试将它们保持在一行:

if (someBoolVar) anotherBoolVar = someBoolVar;

答案 2 :(得分:2)

例如

if (someBoolVar)
    anotherBoolVar = true;

因此当someBoolVartrue时,它会归结为

anotherBoolVar = (whatever boolean value of anotherBoolVar) | true;

总是评估为真。

答案 3 :(得分:2)

对于第一次更改,if构造意味着:

someBoolVar is true ==> anotherBoolVar becomes true
someBoolVar is false ==> anotherBoolVar is unchanged

|=构造意味着:

someBoolVar is true ==> anotherBoolVar becomes (true | initial value) which is always true
someBoolVar is false ==> anotherBoolVar becomes (false | initial value) which is always equal to the initial value

类似的评论适用于第二次改变,尽管@Lasse V. Karlsen提到,&=构造似乎缺少一个代号。

答案 4 :(得分:1)

也许布尔代数上的Wikipedia article有帮助。

这个建议是微观优化,可以快速转变宏观。即时编译器为if()语句生成条件分支,至少Microsoft创建的分支不够智能,无法自行优化代码。您必须查看Mono抖动是否可以通过查看生成的机器代码来做得更好。典型的代码生成如下:

            if (someBoolVar) anotherBoolVar = true;
00007FFD989F3BB1  movzx       eax,cl  
00007FFD989F3BB4  test        eax,eax  
00007FFD989F3BB6  je          00007FFD989F3BBA    // <=== here
00007FFD989F3BB8  mov         dl,1  
00007FFD989F3BBA  etc...

上述机器代码中的JE指令等条件分支对于现代处理器来说很麻烦,它在很大程度上依赖于管道来使代码快速执行。指令解码和微操作生成是提前完成的。对预取器来说也是一个非常重要的事情,它试图猜测缓存中需要提供哪些内存位置,这样执行引擎在需要内存内容时不会停止。与处理器执行引擎的原始执行速度相比,内存非常非常慢。

处理器具有分支预测器,它会跟踪先前执行代码时是否执行了分支。并假设分支将再次以相同的方式运行。如果它猜错了那么管道需要刷新。很多工作都被扔掉了,处理器会在填满时停止运转。如果预取者猜错了,那么可能会发生额外的长时间失误。有一个good SO post可以解释错误预测的后果。

使用布尔代数避免分支,它将生成OR或AND指令,它们只需一个循环,并且永远不会刷新管道。当然是微优化,当代码位于确定程序速度的约10%的代码内时,它只会变成宏。 IDE不会很聪明地告诉你是否是这种情况,只有一个分析器可以告诉你。

Fwiw,有更多这样的微优化,程序员倾向于使用&amp;&amp;和和||运营商不恰当。这些操作员的短路行为总是需要机器代码中的分支。这种行为并不总是需要的,通常它不是和&amp;和|运算符可以生成更快的代码。如果左侧操作数预测不佳,那么它可以使代码慢500%。

答案 5 :(得分:0)

if (someBoolVar)
    anotherBoolVar = true;

相当于

if (someBoolVar)
    anotherBoolVar = true;
else
    anotherBoolVar = anotherBoolVar //Nop

相当于

if (someBoolVar)
    anotherBoolVar = anotherBoolVar | someBoolVar;
else
    anotherBoolVar = anotherBoolVar | someBoolVar //Nop

因为x | true == true和x | false == x

我猜你知道

anotherBoolVar |= someBoolVar

相当于

anotherBoolVar = anotherBoolVar | someBoolVar