像这样:
input: 10010011
(10->01->00->11)
output: 11000110
(11->00->01->10)
input: 11010001
(11->01->00->01)
output: 01000111
(01->00->01->11)
有人有任何想法吗?
答案 0 :(得分:7)
uint32_t reverseByTwo(uint32_t value) {
value = ((value & 0x03030303) << 2) | ((value >> 2) & 0x03030303); // swap adjacent pairs
value = ((value & 0x0F0F0F0F) << 4) | ((value >> 4) & 0x0F0F0F0F); // swap nibbles
value = ((value & 0x00FF00FF) << 8) | ((value >> 8) & 0x00FF00FF); // swap bytes
value = ((value & 0x0000FFFF) << 16) | ((value >> 16) & 0x0000FFFF);
return value;
}
对于64位值,只需为32位半部分添加另一个交换,对于较小的类型,只需省略最后几次交换。
答案 1 :(得分:3)
奇怪的要求。我会这样做:
uint32_t reverseByTwo(uint32_t value)
{
int i;
uint32_t new_value = 0;
for (i = 0; i < 16; i++)
{
new_value <<= 2;
new_value |= (value & 0x3);
value >>= 2;
}
return new_value;
}
在每次迭代时,两个LSB值被放置在new_value的两个LSB中,该LSB向左移动。
对于8位值,
uint8_t reverseByTwo(uint8_t value)
{
int i;
uint32_t new_value = 0;
for (i = 0; i < 4; i++)
{
new_value <<= 2;
new_value |= (value & 0x3);
value >>= 2;
}
return new_value;
}
如果表演非常珍贵,你可以手动展开循环(GCC应该单独执行此操作,但有时不会打扰)并将该函数声明为inline
。
new_value = 0;
// new_value <<= 2; // First time not necessary
new_value |= (value & 0x3);
value >>= 2;
new_value <<= 2;
new_value |= (value & 0x3);
value >>= 2;
new_value <<= 2;
new_value |= (value & 0x3);
value >>= 2;
new_value <<= 2;
new_value |= (value & 0x3);
// value >>= 2;
return new_value;
答案 2 :(得分:2)
将单个字节(字符串)中的位转换为另一个字节的最快方法是自己构建一个数组:
unsigned char rev[256];
rev[0] = 0; /* 00000000 -> 00000000 */
...
rev[147] = 198; /* 10010011 -> 11000110 */
...
rev[198] = 147; /* 11000110 -> 10010011 */
...
rev[255] = 255; /* 11111111 -> 11111111 */
要将数字x转换为其位反转形式,只需编写rev[x]
即可。如果要转换多个字节,例如4字节int
,只需在rev
表中查找4个字节。
在编写此代码时,您需要将二进制转换为另一个基础(此处,我使用十进制),因为C没有二进制常量(比八进制常量有用十倍)。
您也可以将值放入初始化程序中,但您必须计算位置以确保所有内容都在正确的位置。 (也许写一个小程序来做!)
unsigned char rev[256] = {0, ..., 198, ..., 147, ..., 255};
使用正确位置的所有其他数字填写...
。
答案 3 :(得分:1)
$x = (($x & 0x33333333) << 2) | (($x & 0xCCCCCCCC) >> 2);
$x = (($x & 0x0F0F0F0F) << 4) | (($x & 0xFOFOFOFO) >> 4);
$x = (($x & 0x00FF00FF) << 8) | (($x & 0xFF00FF00) >> 8);
$x = (($x & 0x0000FFFF) << 16) | (($x & 0xFFFF0000) >> 16);
为了给予应有的信用,这个算法来自Henry S. Warren,Jr。的“Hacker's Delight”。唯一的区别是书中的算法没有成对反转;它只是颠倒了一点。
答案 4 :(得分:0)
#include <limits.h>
#define INT_BITS (sizeof(int) * CHAR_BIT)
unsigned reverse_bits(unsigned x) {
#define PAIR(i) ((((x) >> (i*2)) & 3) << (INT_BITS - (i+1)*2))
unsigned result = 0;
unsigned i;
for(i = 0; i < INT_BITS/2; i++) {
result |= PAIR(i);
}
return result;
}
虽然这会对unsigned int执行此操作,但您可能希望将int
和unsigned
替换为char
和unsigned char
。
答案 5 :(得分:0)
如果你想要最快的话:
output =
((input & 0xc0) >> 6) |
((input & 0x30) >> 2) |
((input & 0xc) << 2) |
((input & 0x3) << 6);
答案 6 :(得分:0)
你有位(ab cd ef gh)并想要(gh ef cd ab)
如果乘以0x101并以16位int存储,则得到(ab cd ef gh ab cd ef gh)。
然后,您将该数字中的位模式分为两组,每组四位:
所以你必须适当地转移和掩饰
unsigned char swap_bit_pairs(unsigned char b)
{
unsigned int a = 0x101*b;
return ((a >> 6) & 0x33) | ((a >> 2) & 0xCC);
}
所以这可能在6次操作中
编辑: oups!我写了0x66而不是0xCC