2

I need an efficient method with the following signature:

public byte SetBits(byte oldValue, byte newValue, int startBit, int bitCount)

Which returns oldValue, only that starting from its startbit bit up to its startbit + bitcount bit (zero-based), it's replaced with the first bitcount bits of newValue

For example, if:

  • oldValue = 11101101
  • newValue = 10000011
  • startBit = 1
  • bitCount = 2

Then the result would be: 11101111 (the segment 10 in oldValue is replaced with the corresponding 11 segment in newValue)

Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198

3 Answers3

5

Here you go... Bitshift both directions to get the mask... then use it to generate the new byte

public static byte SetBits(byte oldValue, byte newValue, int startBit, int bitCount)
{
    if (startBit < 0 || startBit > 7 || bitCount < 0 || bitCount > 7 
                     || startBit + bitCount > 8)
        throw new OverflowException();

    int mask = (255 >> 8 - bitCount) << startBit;
    return Convert.ToByte((oldValue & (~mask)) | ((newValue << startBit) & mask));
}
Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
deepee1
  • 12,878
  • 4
  • 30
  • 43
0
startBit--; //account for 0 indexing
byte flag = 1 << startBit;
for (int i = startBit; i < bitCount; i++, flag <<= 1)
{
    byte mask = newValue & flag;
    if (mask != 0)
        oldValue |= mask;
    else
        oldValue &= ~(flag);
}
return oldValue;

Some brain compiled code here but it should be along the lines that you want if I read the question correctly.

Jesus Ramos
  • 22,940
  • 10
  • 58
  • 88
  • |= would not zero ones in oldValue – Ohad Schneider Jul 20 '11 at 01:48
  • Thanks for catching that, will fix :) – Jesus Ramos Jul 20 '11 at 01:50
  • `flag` doesn't change during each invocation. You'd have to make `flag` a delegate and `1 << startBit` a lambda for this to work. Or add `flag = 1 << startBit` to the third `for` loop clause. Also, due to the `&=` operating one bit at a time, I think you'd clear out `oldValue` after two iterations through the loop. – Merlyn Morgan-Graham Jul 20 '11 at 01:57
  • Woops I see what you mean, I accidentally put startBit <<= 1 instead of flag, my bad – Jesus Ramos Jul 20 '11 at 01:58
  • @Jesus: I still think you're going to nearly always get `0` for oldValue at the end. For example, first you mask against `0001000`, then against `0010000`. I think you need to build your mask in the loop, *then* apply the mask. Also, I don't think a triple-`&` is going to work, either, if you're trying to *replace* those bits. You probably want to mask `oldValue`, reverse-mask `newValue`, and `|` the results together. – Merlyn Morgan-Graham Jul 20 '11 at 02:02
  • @Merlyn, Yeah you're right maybe I shouldn't code after work haha I'll fix it now. – Jesus Ramos Jul 20 '11 at 02:04
0

If I understood your question, I think this is what you are after:

byte mask = 0xFF;
for (int i = startPos-1; i < numBits; i++)
{
     if ((newValue & (1 << i)) == 1)
     {
          mask = (byte)(mask | (1 << i));
     }
     else
     {
          mask = (byte)(mask &~(1<<i));
     }
 }
 return (byte)(oldValue & mask);

This code is based on some neat tricks from Low Level Bit Hacks You Absolutely Must Know

I know setting a bit in a byte initialized to 0xFF is really a no-op, but I felt the code should be left in as it can help show off what is really going on. I encourage users of the code to optimize it as needed.

zrc210
  • 11
  • 2