我正在尝试实现一个旋转左旋函数,它将整数x左移n位
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]
答案 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