MonoDevelop 建议将 if 语句转换为位操作

MonoDevelop suggests turning if statements into bitwise operations

MonoDevelop 建议转此:

if (someBoolVar)
    anotherBoolVar = true;

进入这个:

anotherBoolVar |= someBoolVar;

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

if (someBoolVar)
    anotherBoolVar = false;

变为:

anotherBoolVar &= !someBoolVar;

谁能解释一下这些陈述是如何相等的?

好吧,功能上它们是等价的。

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

简称:

anotherBoolVar = anotherBoolVar | someBoolVar;

第二个替换也和它替换的代码一样,是这个的缩写:

anotherBoolVar = anotherBoolVar & (!someBoolVar);

在这种情况下,解决方案隐藏在布尔变量的 "bitwise" 性质中。将 的值反转(~ 反转 someBoolVar)将有效地表示 "keep all bits that are set in !someBoolVar and clear out the rest",这意味着如果 someBoolVar 为真,它将被反转为 false,您将有效地清除 anotherBoolVar.


现在,你应该这样做吗

在我看来,没有。代码按原样更具可读性。保留,甚至可能寻找一种方法要求 MonoDevelop 以后不要建议这些东西。

例如

if (someBoolVar)
    anotherBoolVar = true;

所以当 someBoolVartrue 时,它归结为

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

这将始终计算为真。

if (someBoolVar)
    anotherBoolVar = true;

等同于

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

相当于

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

因为 x |真 == 真和 x |假 == x

我假设你知道

anotherBoolVar |= someBoolVar

相当于

anotherBoolVar = anotherBoolVar | someBoolVar

对于第一次更改,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 提到的那样,&= 结构似乎缺少波浪号。

IDE代码推荐往往是一把双刃剑。是的,这些陈述更简洁,但它们也可能令人困惑(因此你的思考)。

if (someBoolVar)
    anotherBoolVar = someBoolVar;

相同
anotherBoolVar |= someBoolVar;

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

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

对于这些类型的 if 语句,我尽量将它们放在一行中:

if (someBoolVar) anotherBoolVar = someBoolVar;

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

建议是微优化,可以快速转宏。即时编译器为 if() 语句生成条件分支,至少微软创建的那些还不够聪明,无法自行优化代码。您必须通过查看生成的机器代码来查看单声道抖动是否可以做得更好。典型的代码生成如下所示:

            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解释了错误预测的后果。

使用布尔代数避免分支,它会产生一个或或与指令,它们需要一个周期并且永远不会刷新管道。当然是微优化,只有当此代码位于决定程序速度的代码的 ~10% 内时,它才会变成宏。 IDE 不会很聪明地告诉你是否是这种情况,只有分析器才能告诉你。

顺便说一下,还有更多类似的微优化,程序员倾向于使用 && 和 ||经营者不当。这些运算符的短路行为总是需要机器代码中的一个分支。这种行为并不总是需要的,通常不需要,& 和 |运算符可以生成更快的代码。如果左侧操作数预测不佳,那么它会使代码慢 500%。