使用位移除以2的幂

时间:2011-02-21 00:09:47

标签: c# bit-manipulation

我有以下任务:

  

使用位移计算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。为什么呢?

4 个答案:

答案 0 :(得分:6)

密切关注舍入行为。

  • /(整数除法)总是向零舍入。
  • 比特转换有什么作用?
  • 你怎么能弥补这种差异?

答案 1 :(得分:6)

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

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

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

000000
111111

这允许我们进一步对整数进行操作以确定一些属性。首先,我们需要找到2的幂,我们将除以(在这种情况下为n)并将二进制移到该位置,然后减去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 :(得分:5)

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

答案 3 :(得分:4)

public int DivideByPowerOf2(int x, int n)
    {

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