按位向左旋转功能

时间:2012-04-13 03:21:19

标签: c

我正在尝试实现一个旋转左旋函数,它将整数x左移n位

  • 例如:rotateLeft(0x87654321,4)= 0x76543218
  • 法律视角:〜& ^ | +<< >>
到目前为止,我有这个:

int rotateLeft(int x, int n) {
  return ((x << n) | (x >> (32 - n)));
}

我已经意识到不适用于签名整数。任何人都有任何想法如何解决这个问题?

所以现在我试过了:

int rotateLeft(int x, int n) {
  return ((x << n) | ((x >> (32 + (~n + 1))) & 0x0f));
}

并收到错误:

错误:测试rotateLeft(-2147483648 [0x80000000],1 [0x1])失败... ......给出15 [0xf]。应为1 [0x1]

6 个答案:

答案 0 :(得分:12)

编译器友好旋转的当前最佳实践是this community-wiki Q&A。来自维基百科的代码不会产生非常好的asm with clang,或gcc早于5.1。

Wikipedia对位旋转a.k.a.循环移位有一个非常好的详细解释。

从那里引用:

unsigned int _rotl(const unsigned int value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
      return value;
    return (value << shift) | (value >> (sizeof(value)*8 - shift));
}

unsigned int _rotr(const unsigned int value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
      return value;
    return (value >> shift) | (value << (sizeof(value)*8 - shift));

在您的情况下,由于您无权访问乘法运算符,因此可以将*8替换为<< 3

编辑您还可以删除if语句,因为您的声明无法使用if。这是一个优化,但没有它你仍然可以获得正确的值。

请注意,如果您真的打算在signed整数上旋转位,则旋转结果的解释将取决于平台。具体而言,它取决于平台是使用Two's Complement还是One's Complement。我想不出一个旋转有符号整数的位有意义的应用程序。

答案 1 :(得分:1)

int rotateLeft(int x, int n) {
  return (x << n) | (x >> (32 - n)) & ~((-1 >> n) << n);
}

更新:(非常感谢@George)

int rotateLeft(int x, int n) {
  return (x << n) | (x >> (32 - n)) & ~(-1 << n);
}

不要使用' - '版本。

int rotateLeft(int x, int n) {
    return (x << n) | (x >> (0x1F & (32 + ~n + 1))) & ~(0xFFFFFFFF << n);
}

//test program
int main(void){
    printf("%x\n",rotateLeft(0x87654321,4));
    printf("%x\n",rotateLeft(0x87654321,8));
    printf("%x\n",rotateLeft(0x80000000,1));
    printf("%x\n",rotateLeft(0x78123456,4));
    printf("%x\n",rotateLeft(0xFFFFFFFF,4));
    return 0;
}
/* result : GCC 4.4.3 and Microsoft(R) 32-bit C 16.00.40219.01
76543218
65432187
1
81234567
ffffffff
*/

答案 2 :(得分:0)

您可以为signed int定义'向左旋转'吗?

我只需将x投射到unsigned int并按照您现在的方式执行旋转。

另一方面说明:您的代码是否需要在不同的体系结构(不仅仅是32位)上工作?您可能希望避免对int bitsize进行硬编码。

答案 3 :(得分:0)

在ISO C中(不知道这是否是你的实现语言,但它看起来确实如此),对带有符号的有符号整数的右移是实现定义的,因此应该避免使用。

如果你正在做bitops,你真的应该首先转换为无符号整数。

答案 4 :(得分:0)

最好的方法是:

int rotateLeft(int x, int n)
{
    _asm
    {
        mov eax, dword ptr [x]
        mov ecx, dword ptr [n]
        rol eax, cl
    }
}

如果您需要在代码中旋转int变量,那么最快的方式是:

#define rotl( val, shift ) _asm mov eax, dword ptr[val] _asm mov ecx, dword ptr [shift] _asm rol eax, cl _asm mov dword ptr [val], eax

val是您旋转的值,shift是旋转的长度。

答案 5 :(得分:0)

我找到一种进行旋转的方法,当您与固定大小的某位人员一起工作并且知道时,该方法很有用:

int rotate_bit_left(int bit_rotating){
 int LastMax = 64;
 bit_rotating = (bit_rotating>=LastMax)? ((bit_rotating << 1 ) | 0x01) : bit_rotating << 1 ;
 return bit_rotating;
 /*
  Here LastMax is 64 because in the exemple I work in the Ascii table where the max is 0111 1111 and this value can be adapted with the value of the last one bit in decimale
 */
}

此功能可以更改为右旋

int rotate_bit_right(int bit_rotating){
 bit_rotating = ((bit_rotating%2)==1)? ((bit_rotating >> 1)| 0x80 ): bit_rotating >> 1 ;
 return bit_rotating; 
 /*
 Because if is a odd number then the last bit is one and we have to put it in the first place
 */
}

请注意,如果您在除Ascii表以外的其他情况下使用以下模式将Hexa数字更改为0x01和0x80,则: 0 ... 0001左旋转 右旋转100 .... 0