2

I have two bytes, they only differ in 1 bit. I want to know what bit this is.

So:

byte a,b;
a=0;
b=2;

ChangedBit(a,b) should give bit 1
ChangedBit(4,5) should give bit 0
ChangedBit(7,3) should give bit 2

Any suggestions are very welcome!!

Thanks,

Erik

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
Enrico
  • 1,937
  • 3
  • 27
  • 40

7 Answers7

2

If they differ by one bit, xor should give you just that bit. So then you could shift to find which?

Perhaps needs some optimisation:

static int ChangedBit(int x, int y)
{
    uint bits = (uint)(x ^ y); // need uint to avoid backfill with shift
    int count = -1;
    while (bits != 0)
    {
        count++;
        bits >>= 1;
    }
    return count;        
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • What a pity that .net is lacking the Bitscan functions. That bites me quite often when doing some bitfiddling. – CodesInChaos Mar 30 '11 at 09:37
  • Marc, I agree that not using Log and double is good, but this optimization is for my application not required. Thanks – Enrico Mar 30 '11 at 09:49
  • Pardon my ignorance, what does `need uint to avoid backfill with shift` mean? (where is the backfill?) – makerofthings7 Mar 09 '13 at 20:25
  • @makerofthings7 the "backfill" is whatever becomes the values on the left-hand-side when you right-shift. When using `uint`, it back-fills with `0`. When using `int`, it back-fills with `0` for +ve values, and `1` for -ve values. – Marc Gravell Mar 09 '13 at 22:11
2

The correct solution would be to do

var bit = Math.Log(a ^ b, 2);

Although of course this leaves open the question of what happens if for any reason more than one bit is different.

You could use

var bit = (int)Math.Log(a ^ b, 2);

to get you the index of the highest different bit, if more than one differ.

Warning: For correctness, any such function should also check that the two arguments a and b are actually different before trying to provide a result. Otherwise you 'll get either a meaningless result or an outright exception. This is true of all the solutions presented here, including this one.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • I think you should convert the result to int. – CodesInChaos Mar 30 '11 at 09:33
  • 1
    IMO, anything that is breaking out `Math.Log` and `double` to solve a bit-fiddling problem is doing it the hard way... – Marc Gravell Mar 30 '11 at 09:44
  • @MarcGravell: I 'd call it the short way, but that's not really the point. More importantly, why write extra code if there's no need to optimize? – Jon Mar 30 '11 at 09:53
  • we don't have the context; we can't assume that. Or at least, not from the question. The OP *has* now indicated that they don't need this, but... – Marc Gravell Mar 30 '11 at 09:55
  • @MarcGravell: True. This would definitely not be a good enough answer if we were talking about a library method. – Jon Mar 30 '11 at 09:57
1

You can do this quite easily:

Math.Log(Math.Abs(a-b), 2)

Update: fixed...

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
1

If you can count from zero, then Math.Log(a^b,2) does the job

kͩeͣmͮpͥ ͩ
  • 7,783
  • 26
  • 40
1
var dif = a ^ b;
int bitNumber = 0;
while (dif != 0 && ((dif & 1) == 0)
{
   dif = dif >> 1;
   ++bitNumber;
}
// bitNumber now contains the zero relative bit that is different.
Richard Schneider
  • 34,944
  • 9
  • 57
  • 73
1

Couldn't resist to write a LINQish version:

var firstBits = new BitArray(new byte[] { 3 });
var secondBits = new BitArray(new byte[] { 17 });

var lhs = firstBits.Cast<bool>().Select((b, i) => new { Bit = b, Index = i });
var rhs = secondBits.Cast<bool>().Select((b, i) => new { Bit = b, Index = i });

var differs = lhs.Zip(rhs, (l, r) => new { Left = l, Right = r })
                 .Where(zipped => zipped.Left.Bit != zipped.Right.Bit)
                 .Select(zipped => new { Index = zipped.Left.Index, LeftBit = zipped.Left.Bit, RightBit = zipped.Right.Bit });

foreach (var diff in differs)
{
    Console.WriteLine(String.Format("Differs in bit {0}:", diff.Index));
    Console.WriteLine(String.Format("   First is set to  {0}", diff.LeftBit));
    Console.WriteLine(String.Format("   Second is set to {0}", diff.RightBit));
}

Update

Due to the fact that the Zip operator is not a default in LINQ, you can get the implementation from Eric out of his blog.

Oliver
  • 43,366
  • 8
  • 94
  • 151
0

Others have observed that where two bytes differ in only one bit, an XOR operation will return a byte in which just that bit is set. But no one has yet suggested what to me is the obvious next step for establishing which bit that is:

public static int WhichBitDiffers(byte a, byte b)
{
    var xor = a ^ b;

    switch(xor)
    {
        case 0x80:
            return 7;
        case 0x40:
            return 6;
        case 0x20:
            return 5;
        case 0x10:
            return 4;
        case 0x8:
            return 3;
        case 0x4:
            return 2;
        case 0x2:
            return 1;
        case 0x1:
            return 0;
        default:
            throw new ArgumentException(
                "Values do not differ in exactly one bit");
    }
}

I bet the compiler / JITter will make this a nice compact jump lookup table, or something along those lines.

AakashM
  • 62,551
  • 17
  • 151
  • 186