2

I am trying to find a simple algorithm that reverses the bits of a number up to N number of bits. For example:

For N = 2:

01 -> 10
11 -> 11

For N = 3:

001 -> 100
011 -> 110
101 -> 101

The only things i keep finding is how to bit reverse a full byte but thats only going to work for N = 8 and thats not always what i need.

Does any one know an algorithm that can do this bitwise operation? I need to do many of them for an FFT so i'm looking for something that can be very optimised too.

WDUK
  • 1,412
  • 1
  • 12
  • 29
  • Do the other bits need to remain untouched or are they zero (or can be set to zero without impact)? If so, it's just a byte-sized bit reversal followed by a shirt. – paxdiablo Jul 04 '20 at 03:41
  • Only the bits up to N need to reversed, the rest are guaranteed to be zero'd anyway. So for example for N = 2 : `0000 0001` becomes `0000 0010` Hope that helps explain it. – WDUK Jul 04 '20 at 03:43
  • The fastest and most efficient way to do this is to just use a _look-up table_ –  Jul 04 '20 at 03:44
  • @MickyD i would still need an algorithm to store the results into the LUT though :) But that is a good idea if an algorithm is taking up a lot of time. – WDUK Jul 04 '20 at 03:46
  • We're not here to write code for you sadly. [ask]. [mcve] –  Jul 04 '20 at 03:46
  • WDUK, yes, but you make that arbitrarily slow since it's only ever done once. – paxdiablo Jul 04 '20 at 03:46
  • Just out of interest, what's the maximum value of `N`? Is it 8, for example? – paxdiablo Jul 04 '20 at 03:49
  • Max is 32 due to integer limits. – WDUK Jul 04 '20 at 03:50
  • 2
    See [Efficient Algorithm for Bit Reversal ... in C](https://stackoverflow.com/questions/746171/efficient-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c). Translate to your language of choice. – dxiv Jul 04 '20 at 03:51
  • @dxiv i saw that earlier - from what i can tell none of them actually let you set a number of bits to reverse leaving the rest intact? – WDUK Jul 04 '20 at 03:53
  • @WDUK Check out the links, too. At worst, you can mask off the bits you want to preserve at the end. Btw, you did not specify a range for `N`. – dxiv Jul 04 '20 at 03:58
  • N is just some number of bits up to 32 since there are a max of 32 bits in an int. The idea is also shown in this image on this answer for N = 3 https://dsp.stackexchange.com/a/8806 – WDUK Jul 04 '20 at 04:05

3 Answers3

3

It is the C# implementation of bitwise reverse operation:

public uint Reverse(uint a, int length)
{
    uint b = 0b_0;
    for (int i = 0; i < length; i++)
    {
        b = (b << 1) | (a & 0b_1);
        a = a >> 1;
    }
    return b;
}

The code above first shifts the output value to the left and adds the bit in the smallest position of the input to the output and then shifts the input to right. and repeats it until all bits finished. Here are some samples:

uint a = 0b_1100;
uint b = Reverse(a, 4); //should be 0b_0011;

And

uint a = 0b_100;
uint b = Reverse(a, 3); //should be 0b_001;

This implementation's time complexity is O(N) which N is the length of the input.

Edit in Dotnet fiddle

Muhammad Vakili
  • 708
  • 4
  • 19
  • @wduk. I suspect this will be as good as you get. It's O(N) (where N is bit width) and the only costs are two shifts and a pair of bit-wise logical operations per bit. The loop work probably costs more than the operations per bit. I can't imagine you getting this done for arbitrary N (1<=N<=32) at less than O(N) – Flydog57 Jul 04 '20 at 16:51
1

Here's a small look-up table solution that's good for (2<=N<=32).

For N==8, I think everyone agrees that a 256 byte array lookup table is the way to go. Similarly, for N from 2 to 7, you could create 4, 8, ... 128 lookup byte arrays.

For N==16, you could flip each byte and then reorder the two bytes. Similarly, for N==24, you could flip each byte and then reorder things (which would leave the middle one flipped but in the same position). It should be obvious how N==32 would work.

For N==9, think of it as three 3-bit numbers (flip each of them, reorder them and then do some masking and shifting to get them in the right position). For N==10, it's two 5-bit numbers. For N==11, it's two 5-bit numbers on either side of a center bit that doesn't change. The same for N==13 (two 6-bit numbers around an unchanging center bit). For a prime like N==23, it would be a pair of 8- bit numbers around a center 7-bit number.

For the odd numbers between 24 and 32 it gets more complicated. You probably need to consider five separate numbers. Consider N==29, that could be four 7-bit numbers around an unchanging center bit. For N==31, it would be a center bit surround by a pair of 8-bit numbers and a pair of 7-bit numbers.

That said, that's a ton of complicated logic. It would be a bear to test. It might be faster than @MuhammadVakili's bit shifting solution (it certainly would be for N<=8), but it might not. I suggest you go with his solution.

Flydog57
  • 6,851
  • 2
  • 17
  • 18
  • By the way, if you do decide to do something like this, consider using @MuhammadVakili's algorithm as a source of truth for your tests. As insane as something like this is, it can work. 35 years ago, I wrote a Z80 multiplication routine that was a similar switch-driven set of shifts and adds. It wasn't much fun, but it worked well (and fast). This was for an embedded device. We wrote our tests off-line against a standard "multiplication table" – Flydog57 Jul 04 '20 at 18:31
-3

Using string manipulation?

static void Main(string[] args)
{
    uint number = 269;
    int numBits = 4;
    string strBinary = Convert.ToString(number, 2).PadLeft(32, '0');
    Console.WriteLine($"{number}");
    Console.WriteLine($"{strBinary}");


    string strBitsReversed = new string(strBinary.Substring(strBinary.Length - numBits, numBits).ToCharArray().Reverse().ToArray());
    string strBinaryModified = strBinary.Substring(0, strBinary.Length - numBits) + strBitsReversed;
    uint numberModified = Convert.ToUInt32(strBinaryModified, 2);
    Console.WriteLine($"{strBinaryModified}");
    Console.WriteLine($"{numberModified}");

    Console.Write("Press Enter to Quit.");
    Console.ReadLine();
}

Output:

269
00000000000000000000000100001101
00000000000000000000000100001011
267
Press Enter to Quit.
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
  • 3
    String manipulation does not really fit in the the "optimised" requirement. – paxdiablo Jul 04 '20 at 06:28
  • Sure, string manipulation is "slow", but we're using C# here...which is not really know for speed anyways (bloated .Net framework anyone?). Without more details about the target system and how fast the FFT actually needs it, I wouldn't knock it without seeing some actual specs and testing results... – Idle_Mind Jul 04 '20 at 19:01