0

I have to write a program that takes bits 3,4,5 and puts them into the place of bits 24,25,26 and then it takes bits 24,25,26 (from the original number) and puts them in the place of bits 3,4,5. The code that I wrote succesfuly transfers 3,4,5 to 24,25,26 but I can't understand why it's not working the other way around.. I also want to ask if there is an easier way to do this..

static void Main()
{
    Console.Write("Please input your number: ");
    int num = Convert.ToInt32(Console.ReadLine());
    int mask = 0;
    int bit = 0;
    int p = 0;
    int numP = 0;

    //take bit 3,4,5 and put them in the place of 24,25,26
    for (int i = 0; i < 3; i++)
    {
        p = 3 + i;
        numP = num >> p;
        bit = numP & 1;
        if (bit == 1)
        {
            mask = 1 << 24 + i;
            num = num | mask;
        }
        else
        {
            mask = ~(1 << 24 + i);
            num = num & mask;
        }
    }

    //take bit 24,25,26 and put them in the place of 3,4,5
    for (int i = 0; i < 3; i++)
    {
        p = 24 + i;
        numP = num >> p;
        bit = numP & 1;
        if (bit == 1)
        {
            mask = 1 << 3 + i;
            num = num | mask;
        }
        else
        {
            mask = ~(1 << 3 + i);
            num = num & mask;
        }
    }
    Console.WriteLine("Your new number is: {0}", num);

}
Darkbound
  • 3,026
  • 7
  • 34
  • 72
  • 1
    You overwrite the last bits. Keep a copy of the number and copy the high bits from it instead. – Mihai Maruseac May 16 '14 at 22:37
  • This is a place where the xor trick is possible, but not preferable. a ^= b; b ^= a; a ^= b; will swap a & b without an extra variable. – ILMTitan May 16 '14 at 23:01

3 Answers3

2

To switch the bits you need to store away the original bits before you copy the new bits in.

As you want to switch three bits that are next to each other with three other bits that are next to each other, it can be done quite easily:

int lo = num & 0x00000038; // get bits 3-5
int hi = num & 0x07000000; // get bits 24-26
num &= ~0x07000038; // clear bits 3-5 and 24-26
num |= lo << 21; // put bits 3-5 in 24-26
num |= hi >> 21; // put bits 24-26 in 3-5

Edit:

Doing the same one bit at a time in a loop; instead of having two loops and copying bits, you can do it with one loop where you swap bits, which solves the problem of the first loop overwriting the bits that you need in the second loop:

int numP, bit1, bit2, mask1, mask2;

//swap bits 3,4,5 with bits 24,25,26
for (int i = 0; i < 3; i++) {
  // get bit 3 (,4,5)
  numP = num >> (3 + i);
  bit1 = numP & 1;
  // get bit 24 (,25,26)
  numP = num >> (24 + i);
  bit2 = numP & 1;
  // shift bit 3 (,4,5) to positon 24 (,25,26)
  bit1 = bit1 << (24 + i);
  // shift bit 24 (,25,26) to position 3 (,4,5)
  bit2 = bit2 << (3 + i);
  // set bit 3 (,4,5) to zero
  mask1 = 1 << (3 + i);
  num = num & ~mask1;
  // set bit 24 (,25,26) to zero
  mask2 = 1 << (24 + i);
  num = num & ~mask2;
  // put bit 3 (,4,5) in bit 24 (,25,26)
  num = num | bit1;
  // put bit 24 (,25,26) in bit 3 (,4,5)
  num = num | bi2;
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • And what is 0x00000038; 0x07000000; ? I am a newbie and I am learning the language atm.. :) – Darkbound May 16 '14 at 22:53
  • @Darkbound: That's hexadecimal representation of numbers where only bits 3-5 and bits 24-26 are set to one. – Guffa May 16 '14 at 22:56
  • Thanks a lot but I need a more nooby way to make it happen most of what you just told me is alien to me, I just took a bath and I understood where is my mistake the 2nd part of my code is actually working fine but I already have bits 3,4,5 at the place of 24,25,26 and thats why when it copies in reverse it takes the modified number, so I would just like some guidance on how to fix and improve my code.. :) – Darkbound May 16 '14 at 23:09
  • @Darkbound: I added some code that is closer to your original code. – Guffa May 16 '14 at 23:26
  • Thanks, now this is a code that I can understand! :) – Darkbound May 17 '14 at 08:48
0

Assuming you are numbering bits from least- to most-significant (the proper way):

3322 2222 2222 1111 1111 11
1098 7654 3210 9876 5432 1098 7654 3210
xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx

Your masks are

  • 0x00000038 (binary: 0000 0000 0000 0000 0000 0000 0011 1000) will extract bits 3-5
  • 0x07000000 (binary: 0000 0111 0000 0000 0000 0000 0000 0000) will extract bits 24-26

The code is easy. This is one way to do it:

public uint exchange_bits( uint a )
{
  uint swapped = (   a & ~( 0x07000038 )       ) // clear bits 3-5 and 24-26
               | ( ( a &    0x00000038 ) << 21 ) // OR in bits 3-5, shifted left 21 bits
               | ( ( a &    0x07000000 ) >> 21 ) // OR in bits 24-26, shifted right 21 bits
               ;
  return swapped ;
}
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
0

It is always my opinion that code should be readable by a human, and only incidentally executable. If you are not running this in a tight loop, you could do the following:

private static int SwapBits(int ind)
{
    BitVector32 bv = new BitVector32(ind);
    BitVector32 bcopy = bv;

    bcopy[1 << 24] = bv[1 << 3];
    bcopy[1 << 25] = bv[1 << 4];
    bcopy[1 << 26] = bv[1 << 5];

    bcopy[1 << 3] = bv[1 << 24];
    bcopy[1 << 4] = bv[1 << 25];
    bcopy[1 << 5] = bv[1 << 26];

    return bcopy.Data;
}

Produces:

old 0x02000028 00000010000000000000000000101000
new 0x05000010 00000101000000000000000000010000

If you are in a tight loop, I would do the following:

private static int SwapBitsInt(int ind)
{
    // mask out the ones we swap
    int outd = ind & ~0x07000038;

    // set the top 3 and bottom 3.  The sections are 21 bits away.
    outd |= (ind & 0x00000038) << 21;
    outd |= (ind & 0x07000000) >> 21;

    return outd;
}

The constants 0x00000038 and 0x07000000 are the results of 1 << 3 | 1 << 4 | 1 << 5 and 1 << 24 | 1 << 25 | 1 << 26. An easy way to find them is to use the "Programmer" mode in Windows Calculator, and click the bits you want.

Mitch
  • 21,223
  • 6
  • 63
  • 86