简体   繁体   English

是否有内置函数来反转位顺序

[英]Is there a built-in function to reverse bit order

I've come up with several manual ways of doing this, but i keep wondering if there is something built-in .NET that does this.我想出了几种手动方法来做到这一点,但我一直想知道是否有内置的 .NET 可以做到这一点。

Basically, i want to reverse the bit order in a byte, so that the least significant bit becomes the most significant bit.基本上,我想反转一个字节中的位顺序,以便最低有效位成为最高有效位。

For example: 1001 1101 = 9D would become 1011 1001 = B9例如:1001 1101 = 9D 会变成 1011 1001 = B9

On of the ways to do this is to use bitwise operations if following this pseudo code:如果遵循以下伪代码,则其中一种方法是使用按位运算:

for (i = 0; i<8; i++)
{
  Y>>1
  x= byte & 1
  byte >>1
  y = x|y;
}

I wonder if there is a function somewhere that will allow me to do all this in one single line .我想知道某处是否有一个函数可以让我在一行中完成所有这些。 Also, do you know the term for such an operation, i'm sure there is one, but i can't remember it at the moment.另外,你知道这种手术的术语吗,我确定有一个,但我现在想不起来了。

Thanks谢谢

I decided to do some performance tests about reversing methods.我决定做一些关于逆向方法的性能测试。

Using Chad's link I wrote the following methods:使用Chad 的链接,我编写了以下方法:

public static byte[] BitReverseTable =
{
    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};
public static byte ReverseWithLookupTable(byte toReverse)
{
    return BitReverseTable[toReverse];
}
public static byte ReverseBitsWith4Operations(byte b)
{
    return (byte)(((b * 0x80200802ul) & 0x0884422110ul) * 0x0101010101ul >> 32);
}
public static byte ReverseBitsWith3Operations(byte b)
{
    return (byte)((b * 0x0202020202ul & 0x010884422010ul) % 1023);
}
public static byte ReverseBitsWith7Operations(byte b)
{
    return (byte)(((b * 0x0802u & 0x22110u) | (b * 0x8020u & 0x88440u)) * 0x10101u >> 16);
}
public static byte ReverseBitsWithLoop(byte v)
{
    byte r = v; // r will be reversed bits of v; first get LSB of v
    int s = 7; // extra shift needed at end
    for (v >>= 1; v != 0; v >>= 1)
    {
        r <<= 1;
        r |= (byte)(v & 1);
        s--;
    }
    r <<= s; // shift when v's highest bits are zero
    return r;
}
public static byte ReverseWithUnrolledLoop(byte b)
{
    byte r = b;
    b >>= 1;
    r <<= 1;
    r |= (byte)(b & 1);
    b >>= 1;

    r <<= 1;
    r |= (byte)(b & 1);
    b >>= 1;

    r <<= 1;
    r |= (byte)(b & 1);
    b >>= 1;

    r <<= 1;
    r |= (byte)(b & 1);
    b >>= 1;

    r <<= 1;
    r |= (byte)(b & 1);
    b >>= 1;

    r <<= 1;
    r |= (byte)(b & 1);
    b >>= 1;

    r <<= 1;
    r |= (byte)(b & 1);
    b >>= 1;

    return r;
}

Then I tested it, and here's the results:然后我测试了一下,结果如下:

Test features:测试功能:

  • 100000000 random bytes to reverse 100000000 随机字节反转
  • OS: Windows 7 x64操作系统:Windows 7 x64
  • CPU: AMD Phenom II 955 (4-core @ 3.2 GHz) CPU:AMD Phenom II 955(4 核 @ 3.2 GHz)
  • RAM: 4GB内存:4GB
  • IDE: Visual Studio 2010 IDE:Visual Studio 2010

Target framework 3.5目标框架 3.5

-----------------------------------------------------
|    Method     | Ticks(x64 mode) | Ticks(x86 mode) |
-----------------------------------------------------
| Loop          |   4861859       |   4079554       |
| Unrolled Loop |   3241781       |   2948026       |
| Look-up table |   894809        |   312410        |
| 3-Operations  |   2068072       |   6757008       |
| 4-Operations  |   893924        |   1972576       |
| 7-Operations  |   1219189       |   303499        |
-----------------------------------------------------

Target framework 4目标框架 4

-----------------------------------------------------
|    Method     | Ticks(x64 mode) | Ticks(x86 mode) |
-----------------------------------------------------
| Loop          |   4682654       |   4147036       |
| Unrolled Loop |   3154920       |   2851307       |
| Look-up table |   602686        |   313940        |
| 3-Operations  |   2067509       |   6661542       |
| 4-Operations  |   893406        |   2018334       |
| 7-Operations  |   1193200       |   991792        |
-----------------------------------------------------

So, look-up table method is not always the fastest :)所以,查表方法并不总是最快的 :)

That can be reasonable, because memory access is slower than CPU registers access, so if some method is compiled and optimized enough to avoid mem access (and to do few operations) it is faster.这可能是合理的,因为内存访问比 CPU 寄存器访问慢,所以如果某些方法被编译和优化到足以避免内存访问(并执行少量操作),它会更快。 (Anyway, the gap is extremely reduced by CPU mem caching) (不管怎样,CPU mem 缓存极大地缩小了差距)

It's also interesting to see the different behaviours in case of x64 or x86 mode, and how 3.5 and 4.0 frameworks performs distinct optimizations.看到 x64 或 x86 模式下的不同行为以及 3.5 和 4.0 框架如何执行不同的优化也很有趣。

No, there isn't anything in the BCL for this.不,BCL 中没有任何内容。

But, assuming you want something fast:但是,假设你想要一些快速的东西:

  • Since there are only 8 bits, it pays to unroll the loop (use 4 statements instead of the for-loop).由于只有 8 位,因此需要展开循环(使用 4 个语句而不是 for 循环)。

  • For an even faster solution, create a 256 entry lookup table.要获得更快的解决方案,请创建一个 256 个条目的查找表。

And you can of course wrap both methods in a function so that the usage only takes 1 statement.您当然可以将这两种方法都包装在一个函数中,这样用法只需要 1 个语句。

I found a page for this problem.我找到了一个解决这个问题的页面

You can loop through bits and and get them in reverse order:您可以遍历位并以相反的顺序获取它们:

public static byte Reverse(this byte b)
{
    int a = 0;
    for (int i = 0; i < 8; i++)
        if ((b & (1 << i)) != 0)
            a |= 1 << (7- i);
    return (byte)a;
}

You can find bit twiddling algorithms in the fxtbook .您可以在fxtbook 中找到位旋转算法。 Chapter 1.14 gives these bit swapping algorithms:第 1.14 章给出了这些位交换算法:

    static uint bitSwap1(uint x) {
        uint m = 0x55555555;
        return ((x & m) << 1) | ((x & (~m)) >> 1);
    }
    static uint bitSwap2(uint x) {
        uint m = 0x33333333;
        return ((x & m) << 2) | ((x & (~m)) >> 2);
    }
    static uint bitSwap4(uint x) {
        uint m = 0x0f0f0f0f;
        return ((x & m) << 4) | ((x & (~m)) >> 4);
    }

Which makes your byte value bit reversal:这使您的字节值位反转:

    public static byte swapBits(byte value) {
        return (byte)(bitSwap4(bitSwap2(bitSwap1(value))));
    }

The x86 JIT compiler doesn't do a great job optimizing this code. x86 JIT 编译器在优化此代码方面做得并不好。 If speed matters then you could use it to initialize a byte[] to make it a fast lookup instead.如果速度很重要,那么您可以使用它来初始化 byte[] 以使其快速查找。

Using @Chads link使用@Chads 链接

byte b; 
b = 0x9D;
b = (byte)((b * 0x0202020202 & 0x010884422010) % 1023); 

Edit : Forgot the cast编辑:忘记演员表

Please see this comprehensive bit-twiddling hacks , namely you want 'Reverse the bits in a byte with 3 operations (64-bit multiply and modulus division)'请参阅此全面的位操作技巧,即您想要“使用 3 次操作(64 位乘法和模除法)反转字节中的位”

int lVal = 0x9D;
int lNewVal = (int)((((ulong)lVal * 0x0202020202UL) & 0x010884422010UL) % 1023);
System.Diagnostics.Debug.WriteLine(string.Format("{0:X2}", lNewVal));

When you run this you will find that the value gets reversed to 0xB9.当您运行它时,您会发现该值被反转为 0xB9。

private UInt32 BitReverse(UInt32 value)
{
  UInt32 left = (UInt32)1 << 31;
  UInt32 right = 1;
  UInt32 result = 0;

  for (int i = 31; i >= 1; i -= 2)
  {
    result |= (value & left) >> i;
    result |= (value & right) << i;
    left >>= 1;
    right <<= 1;
  }
  return result;
}

10 years later. 10年后。 But I hope this helps someone.但我希望这对某人有所帮助。 I did a reverse operation like this:我做了这样的反向操作:

byte Reverse(byte value)
{
    byte reverse = 0;
    for (int bit = 0; bit < 8; bit++)
    {
        reverse <<= 1;
        reverse |= (byte)(value & 1);
        value >>= 1;
    }

    return reverse;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM