使用位移除以2的幂

我有以下任务:

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

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

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

Sotelo发布的代码片段就是您所寻找的代码片段。 它起作用的原因非常重要,特别是对于你理解你的作业。 首先,您必须完全理解2的补码表示。 这是当最高有效位用于将整个二进制表示偏移相应的2的幂时。如果我们只对32位(大多数处理器中的标准)成像,那么我们可以使用右移(>>)来移动最重要的位到最低位。 在这样做时,您将执行算术右移,它将在整个位级表示中复制最高有效位(如果它为负,则为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的可分数的幂。 然后最后分给你两个权力的右移。

密切关注舍入行为。

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

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

 public int DivideByPowerOf2(int x, int n) { return (x + ((x >> 31) & ((1 << n) + ~0))) >> n; }