为啥 ( x & 3 ) 与 ( x mod 4 ) 相同?
Posted
技术标签:
【中文标题】为啥 ( x & 3 ) 与 ( x mod 4 ) 相同?【英文标题】:Why is ( x & 3 ) identical to ( x mod 4 )?为什么 ( x & 3 ) 与 ( x mod 4 ) 相同? 【发布时间】:2011-12-14 03:36:38 【问题描述】:我发现了一些示例源代码,作者似乎使用按位&
运算符而不是%
运算符。但是,当我尝试 x & 4
时,它不会产生与 x % 5
相同的值。
【问题讨论】:
@user988052 仍然是。在 .NET 下快 10%(刚刚测试),代码在这里ideone.com/BLqZP(但请注意,在 ideone 上差异要小得多)。发布 + 不带调试器运行。 @user988052:按位计算,仍然比任何必须处理所有数字的通用mod
实现更快。但是这种优化是如此著名和简单,以至于许多编译器都实现了它,所以是的。 @xanatos:在进行基准测试时,请务必先让 JIT 预热。
@xanatos:当我在谈论 “快得多” 时,我在谈论 bitwise 需要一两个CPU 周期和模数,使用寄存器中 div 的剩余部分,如果不是更多,则需要接近 CPU 20 个周期。因此,当我的意思是“快得多” 时,我指的是快快一个数量级(如果不是更多,10 倍,具体取决于硬件)。正如delnan 所指出的,我说的不是仅仅10%,现在无论如何都可以自动优化; )
@delnan 哇!!这是真的!!!热的时候!!! 天气很暖和!!不,没有区别!尝试了 100 次循环,只查看了最后一个基准。 C# 没有完全优化 & 和 %
编译器只能对无符号值或已知为正的有符号值进行此优化。这意味着有时人类可以在编译器无法执行此优化的情况下执行此优化(因为人类具有编译器缺乏的先验知识)。
【参考方案1】:
这仅适用于 2 的幂。
一般:
x MOD 2^n
相当于:
x AND (2^n - 1)
另请注意,这可能仅适用于 x >= 0
,具体取决于您对 x < 0
的 MOD
的定义。
要了解为什么这行得通,请考虑一下 MOD 的真正含义 - 它只是执行整数除法之后的 余数。在除以 2^n 的情况下,我们实际上只是将二进制值右移 n 位并丢弃任何移出的低位,例如对于 8 位二进制数
a b c d e f g h
如果我们除以 4 = 2^2 那么我们右移 2 位:
0 0 a b c d e f
余数 (g h
) 因整数除法而被丢弃。
如果我们想知道余数,那么我们可以通过应用 0 0 0 0 0 0 1 1
的掩码来提取位 g h
:
a b c d e f g h
AND 0 0 0 0 0 0 1 1
= 0 0 0 0 0 0 g h
请注意,has 的值为 3,在一般情况下仅为 2^n - 1。
让我们用一些实数来试试这个。假设我们要计算 42 / 4 并得到商和余数:
42 = 0 0 1 0 1 0 1 0
为了得到商,我们右移 2 位:
42 / 4 (decimal)
= 0 0 1 0 1 0 1 0 >> 2
= 0 0 0 0 1 0 1 0
= 10 (decimal)
42 MOD 4 (decimal)
= 0 0 1 0 1 0 1 0 AND 0 0 0 0 0 0 1 1
= 0 0 0 0 0 0 1 0
= 2 (decimal)
所以 42/4 = 10 余数 2。
【讨论】:
【参考方案2】:答案很简单,试着用二进制来思考。
0000 = 0 AND 11 = 0000 = 0
0001 = 1 AND 11 = 0001 = 1
0010 = 2 AND 11 = 0010 = 2
0011 = 3 AND 11 = 0011 = 3
0100 = 4 AND 11 = 0000 = 0
0101 = 5 AND 11 = 0001 = 1
0110 = 6 AND 11 = 0010 = 2
0111 = 7 AND 11 = 0011 = 3
...等等。
这与提醒的结果相同(% 是余数,形式上,不是模数)。 它仅适用于 2 的幂,并且仅适用于零和正数。
【讨论】:
以上是关于为啥 ( x & 3 ) 与 ( x mod 4 ) 相同?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在这个例子中有“for(auto& x : v)”而不是“for(auto x : &v)”?
为啥 c++wt 没有与 ExtJs 3.x 集成?以及如何将它与它结合起来?