【问题标题】:How does "&" work for numeric comparison?“&”如何用于数字比较?
【发布时间】:2014-12-20 02:07:19
【问题描述】:
def power_of_two?(n)
  n & (n-1) == 0
end

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

【问题讨论】:

  • 我认为这个函数可能会错误地回答 0 是 2 的幂
  • 你不明白“&”是做什么的,或者你不明白为什么它应该返回n是否是2的幂?
  • 如果 n 是 2 的幂,则此函数确实返回 True。
  • @CarySwoveland 我没有安装 ruby​​。现在我可以说它确实返回 0 是 2 的幂。0 & -1 => 0
  • 这可能是因为 -1 的二进制恭维表示全为 1,而 0 则全为零。所以我们知道:如果 n 是 2 的幂,则函数返回 True。我们知道:如果 n 不是 2 的幂(因为 0 不是 2 的(有限)幂),则函数返回 true。

标签: ruby


【解决方案1】:

& 称为按位与运算符。

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
>>

这就是为什么你可以说42 的幂 数。

【讨论】:

    【解决方案2】:

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

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

    这两个数字的按位与是 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 & (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"。

    这两个数字的按位与是 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。上面的例子只是说明了这个事实,并没有证明这一点……但是,事实就是如此。

    【讨论】:

    • 检查问题下的tag。这是ruby
    • 啊,好吧,原来没评论过
    【解决方案3】:

    我们希望证明这一点

    n & (n-1) == 0
    

    当且仅当n2 的幂。

    我们可以假设n 是一个大于1 的整数。 (其实我会用这个假设来得到一个收缩。)

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

    p = log2(n)
    

    0s 在所有低位位置jj &lt; p。此外,由于(n-1)+1 = nn-1 在所有位偏移j0 &lt;= j &lt; p 处都必须有1。因此,

    n & (n-1) == 0
    

    还有待证明如果n不是2的幂并且

    n & m == 0
    

    然后m != n-1。我假设m = n-1 会得到一个收缩,从而完成证明。

    n 的最高有效位当然是 1。由于n 不是 2 的幂,n 至少有一个其他位等于 1。在这些 1 位中,考虑最高有效位位置j

    由于n &amp; (n-1) == 0n-1 必须在其二进制表示的j 位置有一个0。当我们将1 添加到n-1 时,为了使其等于n,它必须在偏移量j 处有一个1,这意味着n-1 在所有位位置都必须有1 987654360@。此外,(n-1)+1 在添加1 之后的所有位位置j 都为零。但是因为n = (n-1)+1,那只有在j == 0 时才成立,因为n &amp; (n-1) == 0。因此,要做到这一点,n 的最高有效位和最低有效位大多数都等于1,并且所有其他位必须为零。然而,由于n = (n-1)+1,这意味着n-1==0,因此n == 1,需要矛盾。

    (哇!必须有一个更简单的证明!)

    【讨论】:

    • 又是很好的算法方法。我需要向你学习这部分计算机科学。
    【解决方案4】:

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

    1. 如果该位是0 - 将其转换为1 并继续到下一个有效位
    2. 如果位是 1 - 将其转换为 0 并停止。

    这意味着如果一个数字中有多个 1 数字并非所有数字都会被切换(因为您在获得最高有效位之前就停止了)。

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

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

    将两个数字右移相同的数量也会将&amp;ing它们的结果右移相同的数量:

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

    但是0 &gt;&gt; i0,不管i,所以:

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

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

    m & m == 0
    

    但我们也知道:

    m & m == m # for any m
    

    所以m == 0

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

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

    QED

    【讨论】:

    • 这看起来很有希望,但不清楚为什么“n &amp; (n-1) == 0 iff 只有一个1-bit in the number n”遵循“并非所有数字都会切换”。
    • @CarySwoveland - 添加了为什么不是所有数字切换到单个 1 数字的证据
    • 不错,@Uri。我们的证明包含相似之处并不奇怪,但您的证明更直接。但是,我认为它可以简化。如果您从假设n&amp;(n-1)==0 开始,那么您已经证明,当您将1 添加到n-1 以得到m 时,在位置in 有一个1m有一个零,意味着n != n(因为m=n),需要矛盾。因此,n&amp;(n-1) != 0 当n 不是2 的幂。 nm 在位置 i 中具有相同的位也是正确的,但我认为没有必要。
    【解决方案5】:

    在 2 的幂的情况下,它采用二进制形式,即单个位值 1 后跟零。任何这样的值在递减时都将采用 1 的运行形式,因此在使用按位时,由于它必然小于前者,它会将其屏蔽掉。例如

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-06
      • 2012-08-22
      • 2011-03-17
      相关资源
      最近更新 更多