在c中使用位操作向右旋转
Rotate right using bit operation in c
我正在尝试提出一个函数 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;
}
但是,我禁止使用任何转换,允许的操作是~
&
^
|
+
<<
和 >>
。谁能帮我解决这个问题?
根据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));
}
基本上你所要做的就是:
使用右移将所有内容右移 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
(这样就不会发生符号扩展或负向左移),然后取模 n
乘以 32 (% 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;
}
并为你们这些极简主义者打成一条线:
unsigned rotr(unsigned x, unsigned n) {
return (x >> n % 32) | (x << (32-n) % 32);
}
旋转是通过左右移动的组合完成的。
移动有符号整数的符号位是个问题。建议转换为 unsigned
以执行移位。 @The Paramagnetic Croissant
An example of implementation-defined behavior is the propagation of the high-order bit when a signed integer is shifted right.
移位位宽或更多是个问题。将实际移动限制为 n modulo Bit_width
。当 n == 0
.
时,OP 的 (...<<(32-n));
代码是一个问题
OP 的示例看起来更像是左旋转。将假设函数应该向右旋转。 (0x87654321,4)
--> 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;
[Edit2] 以为我会形成一个 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));
}
我正在尝试提出一个函数 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;
}
但是,我禁止使用任何转换,允许的操作是~
&
^
|
+
<<
和 >>
。谁能帮我解决这个问题?
根据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));
}
基本上你所要做的就是:
使用右移将所有内容右移 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
(这样就不会发生符号扩展或负向左移),然后取模 n
乘以 32 (% 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;
}
并为你们这些极简主义者打成一条线:
unsigned rotr(unsigned x, unsigned n) {
return (x >> n % 32) | (x << (32-n) % 32);
}
旋转是通过左右移动的组合完成的。
移动有符号整数的符号位是个问题。建议转换为 unsigned
以执行移位。 @The Paramagnetic Croissant
An example of implementation-defined behavior is the propagation of the high-order bit when a signed integer is shifted right.
移位位宽或更多是个问题。将实际移动限制为 n modulo Bit_width
。当 n == 0
.
(...<<(32-n));
代码是一个问题
OP 的示例看起来更像是左旋转。将假设函数应该向右旋转。 (0x87654321,4)
--> 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;
[Edit2] 以为我会形成一个 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));
}