C中的位旋转

时间:2012-01-23 07:28:57

标签: c bit-manipulation

问题:C编程语言的练习2-8,“写一个函数rightrot(x,n),它返回整数x的值,向右旋转n个位置。”

我已经按照我所知道的方式完成了这一切。这是我遇到的问题。拿一个给定数字进行本练习,比如说29,然后将它旋转到一个位置 11101,它变为11110或30.假设为了论证,我们正在处理的系统的无符号整数类型大小为32位。让我们进一步说,我们将数字29存储在无符号整数变量中。在内存中,数字将在它之前有27个零。所以当我们使用几种算法中的一种旋转29右边时,我的数据是2147483662.这显然不是理想的结果。

unsigned int rightrot(unsigned x, int n) {
    return (x >> n) | (x << (sizeof(x) * CHAR_BIT) - n);
}

从技术上讲,这是正确的,但我认为11101前面的27个零是无关紧要的。我还尝试了其他一些解决方案:

int wordsize(void) {    // compute the wordsize on a given machine...
    unsigned x = ~0;
    int b;
    for(b = 0; x; b++)
        x &= x-1;
    return x;
}

unsigned int rightrot(unsigned x, int n) {
    unsigned rbit;
    while(n --) {
        rbit = x >> 1;
        x |= (rbit << wordsize() - 1);
    }
    return x;

这个最后也是最后一个解决方案就是我认为我拥有它的解决方案,一旦我走到尽头,我将解释它失败的地方。我相信你会看到我的错误......

int bitcount(unsigned x) {
    int b;
    for(b = 0; x; b++)
        x &= x-1;
    return b;
}

unsigned int rightrot(unsigned x, int n) {
    unsigned rbit;
    int shift = bitcount(x);
    while(n--) {
        rbit = x & 1;
        x >>= 1;
        x |= (rbit << shift);
    }
}

这个解决方案给出了我想要的30的预期答案,但是如果你使用x的数字,比如说31(11111),那么就会出现问题,特别是结果是47,使用一个用于n。我没有想到这个,但如果使用8(1000)这样的数字然后混乱。 8中只有一个位,所以这种转变肯定是错误的。我在这一点上的理论是前两个解决方案是正确的(大多数),我只是缺少一些东西......

4 个答案:

答案 0 :(得分:8)

按位旋转始终必须在给定宽度的整数范围内。在这种情况下,当你假设一个32位整数时,2147483662(0b10000000000000000000000000001110)确实是正确答案;你没有做错什么!

任何合理的定义都不会将

0b11110视为正确的结果,因为继续使用相同的定义正确旋转它永远不会让您回原始输入。 (考虑另一个正确的旋转会给0b1111,并继续旋转,这将无效。)

答案 1 :(得分:3)

在我看来,在本练习之前的本书部分的精神将使读者在不知道整数或任何其他类型的大小(以位为单位)的情况下完成此问题。本节中的示例不需要该信息;我也不相信这些练习。

不管我的信念如何,这本书还没有通过第2.9节引入sizeof运算符,所以计算类型大小的唯一方法是用手计算位数&#34;。

但我们不需要为此烦恼。无论数据类型中有多少位,我们都可以在n个步骤中进行位旋转,方法是一次旋转一位。

仅使用本书所涵盖的语言部分直到第2.9节,这里是我的实现(使用整数参数,返回一个整数,由练习指定):循环n次,x&gt; ;&GT;每次迭代1次;如果x的旧低位为1,则设置新的高位。

int rightrot(int x, int n) {
    int lowbit;

    while (n-- > 0) {
        lowbit = x & 1;            /* save low bit */
        x = (x >> 1) & (~0u >> 1); /* shift right by one, and clear the high bit (in case of sign extension) */
        if (lowbit)
            x = x | ~(~0u >> 1);   /* set the high bit if the low bit was set */
    }

    return x;
}

答案 2 :(得分:0)

您可以使用二进制搜索在32位值中找到第一个“1”的位置。然后记下LSB位置的位,右移该值所需的位数,并将LSB位置于第一个'1'的位置。

答案 3 :(得分:0)

int bitcount(unsigned x) {
    int b;
    for(b = 0; x; b++)
        x &= x-1;
    return b;
}

unsigned rightrot(unsigned x,int n) {
   int b = bitcount(x);
   unsigned a = (x&~(~0<<n))<<(b-n+1);
   x>> = n;
   x| = a;
}