使用c中的位操作向右旋转

时间:2015-02-03 15:55:54

标签: c bit-manipulation bit

我正在努力想出一个函数int rotateRight (int x, int n)x向右移动n rotateRight(0x87654321,4) = 0x76543218 。例如,

int rotateRight(int x, int n) {
  int mask = (((1 << n)-1)<<(32-n));
  int reserve = (int)((unsigned) (x&mask) >>(32-n));
  return (x << n) | reserve; 
}

这是我到目前为止所做的:

~

但是,我禁止使用任何广告投放,允许的操作是& ^ | + << >>和{ {1}}。任何人都可以帮我解决这个问题吗?

3 个答案:

答案 0 :(得分:3)

基本上你所要做的就是:

  • 使用右移将所有内容右移n位:>>

  • 将您要旋转的位一直向左移动:<<

  • 将移位的右移位和左移位与or合并:|

使用您需要的函数签名查看此代码以获取示例实现:

int rotateRight(int x, int n) {

    //if n=4, x=0x12345678:

    //shifted = 0x12345678 >> 4 = 0x01234567
    int shifted = x >> n;

    //rot_bits = (0x12345678 << 28) = 0x80000000
    int rot_bits = x << (32-n);

    //combined = 0x80000000 | 0x01234567 = 0x81234567
    int combined = shifted | rot_bits;

    return combined;
}

这种实施方式并不安全,至少在没有一些保证的情况下 - 即x始终为正,n为正,始终为<= 32

如果传入一个负整数进行移位,它将无法正常工作,因为它会对最左边的位进行符号扩展。如果您希望此函数适用于所有整数,则应将所有类型从int更改为unsigned int(这样就不会发生符号扩展或负向左移),然后以模{{{ 1}} by 32(n)。这是函数的安全版本:

% 32

为你的极简主义者打高尔夫球:

unsigned int rotateRight(unsigned int x, unsigned int n) {

    //needed so you don't right shift more than int width
    n %= 32;

    //needed so you don't left shift more than int width
    unsigned int leftshift_val = (32-n) % 32 

    unsigned int shifted = x >> n;
    unsigned int rot_bits = x << leftshift_val;
    unsigned int combined = shifted | rot_bits;

    return combined;
}

答案 1 :(得分:1)

通过左右移位的组合完成旋转。

移位有符号整数的符号位是个问题。建议转换为unsigned以执行转换。 @The Paramagnetic Croissant

  

实现定义行为的一个示例是当有符号整数向右移位时传输高阶位。

移位位宽或更大是一个问题。将实际转移限制为n modulo Bit_width(...<<(32-n));时,OP n == 0代码存在问题。

OP的例子看起来更像是左旋转。将假设该功能应该向右旋转。 (0x87654321,4) - &gt; 0x18765432@Mark Shevchenko

int的宽度不得超过32。


#include <limits.h>
#define INT_BIT_WIDTH (sizeof (int) * CHAR_BIT)

int rotateRight(int x, int n) {
  unsigned xu = x;
  unsigned nu = n;
  nu %= INT_BIT_WIDTH;
  unsigned y = xu >> nu;
  if (nu > 0) {
    y |= xu << (INT_BIT_WIDTH - nu);
  }
  return y;
}

[编辑]由于OP仅限于~ & ^ | + << >>,请使用以下替代代码 注意:在极少数情况下,int的宽度不是2的幂,这是一个问题。

// nu %= INT_BIT_WIDTH;
nu &= INT_BIT_WIDTH - 1;

[编辑2]以为我会形成一个unsigned简约解决方案,受到@RPGillespie的启发,因为OP无法使用%

#include <limits.h>
#define UNS_WIDTH    (sizeof (unsigned) * CHAR_BIT)
#define UNS_WIDTH_M1 (UNS_WIDTH - 1)

unsigned unsigned_rotate_right(unsigned x, unsigned n) {
  return (x >> (n & UNS_WIDTH_M1)) | (x << ((UNS_WIDTH - n) & UNS_WIDTH_M1));
}

答案 2 :(得分:0)

根据this explanation,可以通过以下实现完成轮换。

#include<stdio.h>
#define INT_BITS 32

/*Function to left rotate n by d bits*/
int leftRotate(int n, unsigned int d)
{
   /* In n<<d, last d bits are 0. To put first 3 bits of n at
     last, do bitwise or of n<<d with n >>(INT_BITS - d) */
   return (n << d)|(n >> (INT_BITS - d));
}