【问题标题】:Dividing by power of 2 using bit shifting使用位移除以 2 的幂
【发布时间】:2019-09-22 04:52:36
【问题描述】:

我有以下任务:

使用位移计算x/(2^n),为0 <= n <= 30

要求:向零舍入。

例子:

divpwr2(15,1) = 7
divpwr2(-33,4) = -2

合法运营商:! ~ & ^ | + << >>

最大运营商数量:15

这是我目前得到的:

public int DivideByPowerOf2(int x, int n)
{
    //TODO: find out why DivideByPowerOf2(-33,4) = -3 instead of -2
    return x >> n;
}

DivideByPowerOf2(15,1) = 7 没问题。

但是 DivideByPowerOf2(-33,4) = -3 而不是 -2。为什么?

【问题讨论】:

  • 闻起来像作业......
  • 您会感兴趣地注意到 33 >> 4 = 2。所以,问题是,>> 运算符对负数有什么作用?
  • @Joey 也许是。他不是要我们为他做功课——他是在问我们为什么他的职能没有达到他的预期。
  • 提示:哪个位是符号位,当你移位时它会发生什么?
  • @glow:问的还是很差。不过现在已经改变了。

标签: c# bit-manipulation


【解决方案1】:

在自己寻找一个好的答案之后,我偶然发现了这个并且能够得到一个有效的 sn-p。让我帮助向将来可能会发现这一点的其他人解释这一点。

(x + ((x >> 31) & ((1 << n) + ~0))) >> n

此代码的 sn-p 是您正在寻找的,由 Sotelo 发布。它起作用的原因是非常重要的,尤其是对于你理解你的作业。首先,您必须完全理解 2 的补码表示。这是最高有效位用于将整个二进制表示偏移相应的 2 次幂。 如果我们只成像 32 位(大多数处理器中的标准),那么我们可以使用右移 (>>) 将最高有效位移动到最低有效位。在这样做时,您将进行算术右移,它将在整个位级别表示中复制该最高有效位(如果为负,则为 1)。在 6 位二进制表示中,这将导致

000000
111111

这允许我们进一步对整数进行操作以确定一些属性。首先,我们需要找到要除以(在本例中为 n)的 2 的幂,并将二进制移到该位置,然后减去 1。例如,让我们使用 3 或 8 的幂。

(000001 << 3) -1
000111

既然我们拥有这两种二进制表示,我们将把它们放在一起

111111 & 000111 = 000111 (case 1)
000000 & 000111 = 000000 (case 2)

现在假设 x 是奇数或偶数(分别为案例 1 和案例 2),我们可以将 x 添加到此并得到一个完美的 2 幂的数字(如果我们除以 2 的幂,我们将得到一个适当的回答)。下面是几个 x = 8、10、-8、-12 的例子。

001000 + 000000 = 001000
001010 + 000000 = 001010
now for the negatives that plague you
111000 + 000111 = 111111
110100 + 000111 = 111011

现在最后一步是将这些数字除以我们的 n 次方。如上所述,除以 8 为 3。

001000 >> 3 = 000001 or 1 in decimal (8/8 = 1)
001010 >> 3 = 000001 or 1 in decimal (10/8 = 1 because of truncation)
111111 >> 3 = 111111 or -1 in decimal (-8/8 = -1)
111011 >> 3 = 111111 or -1 in decimal (-12/8 = -1 because of truncation)

所以你有它。您的首要任务是找出它是负数还是正数,然后从负数中获取与您的 2 -1 幂对应的位。将此添加到您的 x 以获得二进制中 2 整除数的幂。然后最后将你的二分之一右移。

【讨论】:

    【解决方案2】:

    密切注意舍入行为。

    • /(整数除法)总是向零舍入。
    • 位移有什么作用?
    • 您如何弥补这种差异?

    【讨论】:

      【解决方案3】:
      public int DivideByPowerOf2(int x, int n)
          {
      
              return (x + ((x >> 31) & ((1 << n) + ~0))) >> n;
          }
      

      【讨论】:

        【解决方案4】:

        由于它们的二进制补码表示,负数在二进制表示中是一个。也许阅读two's complement 会有所帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-09-04
          • 1970-01-01
          • 2014-11-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-30
          相关资源
          最近更新 更多