"&"工作数字比较?

时间:2014-12-18 20:23:56

标签: ruby

def power_of_two?(n)
  n & (n-1) == 0
end

此方法检查给定数字n是否为2的幂。 这是如何运作的?我不明白&

的用法

5 个答案:

答案 0 :(得分:2)

&称为按位AND运算符。

The AND operator逐位遍历两个提供的整数的二进制表示。如果两个整数中相同位置的位为1,则结果整数将该位设置为1.如果不是,该位将设置为0:

(a = 18).to_s(2)     #=> "10010"
(b = 20).to_s(2)     #=> "10100"
(a & b).to_s(2)      #=> "10000"

如果数字已经是2的幂,那么少一个将导致只设置了低阶位的二进制数。使用&将无能为力。

  • 8的示例:0100 & (0100 - 1) - > (0100 & 0011) - > 0000

要理解它,请遵循“How does this bitwise operation check for a power of 2?”。

IRB的例子:

>> 4.to_s(2)
=> "100"
>> 3.to_s(2)
=> "11"
>> 4 & 3
=> 0
>>

这就是为什么你可以说4 2 号的力量。

答案 1 :(得分:1)

“&”是一个有点“AND”(见http://calleerlandsson.com/2014/02/06/rubys-bitwise-operators/)运算符。它比较两个数字,如以下示例中所述:

假设n = 4(这是2的幂)。这意味着n-1 = 3。在二进制文件中(我用引号中的1和0编写,如“1101011101”,所以我们可以看到这些位)我们有n =“100”和n-1 =“011”。

这两个数字的逐位AND是0 =“000”(在下面,每列只包含一个1,从不包含两个1)

100          <-- this is n, n=4
011          <-- this is n-1, n-1=3
---
000          <-- this is n & (n-1)

作为另一个例子,现在假设n = 14(不是2的幂),因此n-1 = 13。在那种情况下,n =“1110”并且n-1 =“1101”,并且我们有n&amp; (n-1)= 12

1110         <-- this is n, n=14
1101         <-- this is n-1, n-1=13
----
1100         <-- this is n & (n-1)

在上面的例子中,n和n-1的前两列都包含1,因此这些列的AND是1。

好吧,让我们考虑一个最后一个例子,其中n再次是2的幂(如果不是为什么“poweroftwo?”按原样写的话,这应该是非常明确的。假设n = 16(这是一个权力)两个)。

假设n = 16(这是2的幂)。这意味着n-1 = 15因此我们有n =“10000”和n-1 =“01111”。

这两个数字的逐位AND是0 =“00000”(在下面,每列只包含一个1,从不包含两个1)

10000          <-- this is n, n=16
01111          <-- this is n-1, n-1=15
---
00000          <-- this is n & (n-1)

警告:在n = 0的特殊情况下,函数“power_of_two?”即使n = 0不是2的幂,它也会返回True。这是因为0表示为全零的位串,任何与零相关的任何值都为零。

所以,一般来说,功能“power_of_two?”当且仅当n是2的幂或n为零时才返回True。上面的例子只说明了这个事实,他们并没有证明这一点......但事实并非如此。

答案 2 :(得分:1)

从二进制数减去1的过程是从最低有效位开始:

  1. 如果该位为0 - 将其转为1并继续下一个有效位
  2. 如果该位为1 - 将其转为0并停止。
  3. 这意味着如果数字中有多个1数字,则不会切换所有数字(因为您在获得最高位之前停止了)。

    我们说我们的号码1中的第一个 n位于i位置。如果我们向右移动数字n,我们将得到数字的一部分,当我们减少一个数字时没有改变,让我们称之为m。如果我们改变数字n-1,我们应该得到相同的数字m ,正是因为当我们减少一个时,它是没有改变的部分:

    n >> i == m
    (n - 1) >> i == m
    

    将相同数量的两个数字向右移动也会向&的结果移动相同的数量:

    (n >> i) & ((n - 1) >> i) == 0 >> i
    

    但是0 >> i0,无论i,所以:

    (n >> i) & ((n - 1) >> i) == 0
    

    让我们把m放在我们知道的地方:

    m & m == 0
    

    但我们也知道:

    m & m == m # for any m
    

    所以m == 0

    因此n & (n - 1) == 0当且仅当数字1中最多有一个n位。

    最多只有一个1位的唯一数字是2的所有(非负)幂(前导1)和后面的非负数量的零),以及数字0

    QED

答案 3 :(得分:1)

我们希望证明

n & (n-1) == 0

当且仅当n具有2的权力。

我们可以假设n是一个大于1的整数。 (事实上​​,我将使用这个假设来获得收缩。)

如果n2的幂,则其二进制表示在位偏移处有1

p = log2(n)

0位于所有低位位jj < p。此外,由于(n-1)+1 = nn-1在所有位偏移1j上必须0 <= j < p。因此,

n & (n-1) == 0

如果n不是2

的力量,那仍然需要证明
n & m == 0

然后m != n-1。我假设m = n-1并且将获得收缩,从而完成证明。

n最重要的位当然是1.由于n不是2的幂,n至少有一个等于{{1}的位}}。在这些1位中,考虑最高有效位1处的那个。

由于jn & (n-1) == 0必须在其二进制表示的n-1位置0。当我们将j添加到1时,为了使其n-1,它必须在偏移n处有1,这意味着j必须所有位位置都有n-1&lt; 1&gt; 1。此外,j在所有比特位置都具有零&lt;添加(n-1)+1j。但是从1开始,只有n = (n-1)+1,才能成为j == 0。因此,为此,n & (n-1) == 0最高有效位和最低有效位大多数都等于n,所有其他位必须等于零。但是,由于1,这意味着n = (n-1)+1,因此n-1==0,这是必然的矛盾。

(哇!这是一个更容易证明!)

答案 4 :(得分:0)

在幂为2的情况下,它采用值为1的单个位的二进制形式,后跟零。递减时的任何这样的值将采用1的运行形式,因此当使用按位时 - 并且由于它必然小于前者,它将掩盖它。 E.g。

0b1000&amp; (0b1000 - 1)= 0b1000&amp; 0b111 = 0

所以,任何东西(num-1)都可能变成,这里的关键是触及num的最高位,通过减少它,我们清除它。

另一方面,如果数字不是2的幂,则结果必须为非零。

背后的原因是操作总是可以在不触及最高位的情况下进行,因为在路上总会有一个非零位,所以至少最高位使它成为了掩码并将显示在结果中。