Is there a way to convert an int to a bitmask?
example:
int i = 33;
should be converted to (not sure of the datatype)
bool[] bitmask = new[] {true, false, false, false, false, true};
Update
In reaction to most answers:
I need to do this:
BitArray bits = new BitArray(BitConverter.GetBytes(showGroup.Value));
List<String> showStrings = new List<string>();
for (int i = 0; i < bits.Length; i++)
{
if(bits[i])
showStrings.Add((i+1).ToString().PadLeft(2, '0'));
}
How would that go without converting it to a bitarray?
An int already is a bitmask. If you want to twiddle the bits, you can use bitwise operators freely on ints. If you want to convert the int to an enum that has the Flags attribute, a simple cast will suffice.
Found it
BitArray bits = new BitArray(System.BitConverter.GetBytes(showGroup.Value));
You could construct a bool[32] and loop through all bits in the int, masking it with 2^(loop counter) and setting the bools in the array appropriately.
Are you sure you need this, though? Most operations with bitmasks work with ints directly.
To answer the question in your edit:
int val = 35;
List<string> showStrings = new List<string>();
for (int i = 0; i < 32; i++)
{
if (( (1 << i) & val) > 0)
{
showStrings.Add((i + 1).ToString().PadLeft(2, '0'));
}
}
prints:
01
02
06
Not the most obvious solution if you're not used to bit arithmetic, true. Mask each bit in the integer value with 2^(bit-index), and if the resulting value is greater than zero (indicating that the bit at that index is set), do something. 1 << i (left-shifting) is equivalent to 2^i, and may have the same performance characteristics once JITted, but I'm used to this form.
Expressed as a macro-like method:
bool IsSet(int val, int index)
{
return (( (1 << (index-1)) & val) > 0);
}
int val = 33;
var bitarray = new BitArray(new[] { val });
var att = bitarray.Cast<bool>().ToArray();
Since you asked, here is a solution without using BitArray:
// First define a bitmask enum for the bits you are interested in
[Flags]
public enum BitFlags
{
Flag1 = 1,
Flag2 = 2,
Flag3 = 4,
Flag4 = 8,
Flag5 = 16
// ...
}
int index = 0;
List<string> showStrings = new List<string>();
foreach(int flag in Enum.GetValues(typeof(BitFlags))cast<int>())
{
index += 1;
if ((input & flag) == flag)
showStrings.Add(index.ToString().PadLeft(2, '0'));
}
It is about the same amount of code, with negligible performance difference. It does however let you strongly define your bit values and you can choose to omit bits in the BitFlags enum that you don't care about.
Related
I have a list of 128 32 bit numbers, and I want to know, is there any combination of 12 numbers, so that all numbers XORed give the 32 bit number with all bits set to 1.
So I have started with naive approach and took combinations generator like that:
private static IEnumerable<int[]> Combinations(int k, int n)
{
var state = new int[k];
var stack = new Stack<int>();
stack.Push(0);
while (stack.Count > 0)
{
var index = stack.Count - 1;
var value = stack.Pop();
while (value < n)
{
state[index++] = value++;
if (value < n)
{
stack.Push(value);
}
if (index == k)
{
yield return state;
break;
}
}
}
}
and used it like that (data32 is an array of given 32bit numbers)
foreach (var probe in Combinations(12, 128))
{
int p = 0;
foreach (var index in probe)
{
p = p ^ data32[index];
}
if (p == -1)
{
//print out found combination
}
}
Of course it takes forever to check all 23726045489546400 combinations...
So my question(s) are - am I missing something in options how to speedup the check process?
Even if I do the calculation of combinations in partitions (e.g. I could start like 8 threads each will check combination started with numbers 0..8), or speed up the XORing by storing the perviously calculated combination - it is still slow.
P.S. I'd like it to run in reasonable time - minutes, hours not years.
Adding a list of numbers as was requested in one of the comments:
1571089837
2107702069
466053875
226802789
506212087
484103496
1826565655
944897655
1370004928
748118360
1000006005
952591039
2072497930
2115635395
966264796
1229014633
827262231
1276114545
1480412665
2041893083
512565106
1737382276
1045554806
172937528
1746275907
1376570954
1122801782
2013209036
1650561071
1595622894
425898265
770953281
422056706
477352958
1295095933
1783223223
842809023
1939751129
1444043041
1560819338
1810926532
353960897
1128003064
1933682525
1979092040
1987208467
1523445101
174223141
79066913
985640026
798869234
151300097
770795939
1489060367
823126463
1240588773
490645418
832012849
188524191
1034384571
1802169877
150139833
1762370591
1425112310
2121257460
205136626
706737928
265841960
517939268
2070634717
1703052170
1536225470
1511643524
1220003866
714424500
49991283
688093717
1815765740
41049469
529293552
1432086255
1001031015
1792304327
1533146564
399287468
1520421007
153855202
1969342940
742525121
1326187406
1268489176
729430821
1785462100
1180954683
422085275
1578687761
2096405952
1267903266
2105330329
471048135
764314242
459028205
1313062337
1995689086
1786352917
2072560816
282249055
1711434199
1463257872
1497178274
472287065
246628231
1928555152
1908869676
1629894534
885445498
1710706530
1250732374
107768432
524848610
2791827620
1607140095
1820646148
774737399
1808462165
194589252
1051374116
1802033814
I don't know C#, I did something in Python, maybe interesting anyway. Takes about 0.8 seconds to find a solution for your sample set:
solution = {422056706, 2791827620, 506212087, 1571089837, 827262231, 1650561071, 1595622894, 512565106, 205136626, 944897655, 966264796, 477352958}
len(solution) = 12
solution.issubset(nums) = True
hex(xor(solution)) = '0xffffffff'
There are 128C12 combinations, that's 5.5 million times as many as the 232 possible XOR values. So I tried being optimistic and only tried a subset of the possible combinations. I split the 128 numbers into two blocks of 28 and 100 numbers and try combinations with six numbers from each of the two blocks. I put all possible XORs of the first block into a hash set A, then go through all XORs of the second block to find one whose bitwise inversion is in that set. Then I reconstruct the individual numbers.
This way I cover (28C6)2 × (100C6)2 = 4.5e14 combinations, still over 100000 times as many as there are possible XOR values. So probably still a very good chance to find a valid combination.
Code (Try it online!):
from itertools import combinations
from functools import reduce
from operator import xor as xor_
nums = list(map(int, '1571089837 2107702069 466053875 226802789 506212087 484103496 1826565655 944897655 1370004928 748118360 1000006005 952591039 2072497930 2115635395 966264796 1229014633 827262231 1276114545 1480412665 2041893083 512565106 1737382276 1045554806 172937528 1746275907 1376570954 1122801782 2013209036 1650561071 1595622894 425898265 770953281 422056706 477352958 1295095933 1783223223 842809023 1939751129 1444043041 1560819338 1810926532 353960897 1128003064 1933682525 1979092040 1987208467 1523445101 174223141 79066913 985640026 798869234 151300097 770795939 1489060367 823126463 1240588773 490645418 832012849 188524191 1034384571 1802169877 150139833 1762370591 1425112310 2121257460 205136626 706737928 265841960 517939268 2070634717 1703052170 1536225470 1511643524 1220003866 714424500 49991283 688093717 1815765740 41049469 529293552 1432086255 1001031015 1792304327 1533146564 399287468 1520421007 153855202 1969342940 742525121 1326187406 1268489176 729430821 1785462100 1180954683 422085275 1578687761 2096405952 1267903266 2105330329 471048135 764314242 459028205 1313062337 1995689086 1786352917 2072560816 282249055 1711434199 1463257872 1497178274 472287065 246628231 1928555152 1908869676 1629894534 885445498 1710706530 1250732374 107768432 524848610 2791827620 1607140095 1820646148 774737399 1808462165 194589252 1051374116 1802033814'.split()))
def xor(vals):
return reduce(xor_, vals)
A = {xor(a)^0xffffffff: a
for a in combinations(nums[:28], 6)}
for b in combinations(nums[28:], 6):
if a := A.get(xor(b)):
break
solution = {*a, *b}
print(f'{solution = }')
print(f'{len(solution) = }')
print(f'{solution.issubset(nums) = }')
print(f'{hex(xor(solution)) = }')
Arrange your numbers into buckets based on the position of the first 1 bit.
To set the first bit to 1, you will have to use an odd number of the items in the corresponding bucket....
As you recurse, try to maintain an invariant that the number of leading 1 bits is increasing and then select the bucket that will change the next 0 to a 1, this will greatly reduce the number of combinations that you have to try.
I have found a possible solution, which could work for my particular task.
As main issue to straitforward approach I see a number of 2E16 combinations.
But, if I want to check if combination of 12 elements equal to 0xFFFFFFFF, I could check if 2 different combinations of 6 elements with opposit values exists.
That will reduce number of combinations to "just" 5E9, which is achievable.
On first attempt I think to store all combinations and then find opposites in the big list. But, in .NET I could not find quick way of storing more then Int32.MaxValue elements.
Taking in account idea with bits from comments and answer, I decided to store at first only xor sums with leftmost bit set to 1, and then by definition I need to check only sums with leftmost bit set to 0 => reducing storage by 2.
In the end it appears that many collisions could appear, so there are many combinations with the same xor sum.
Current version which could find such combinations, need to be compiled in x64 mode and use (any impovements welcomed):
static uint print32(int[] comb, uint[] data)
{
uint p = 0;
for (int i = 0; i < comb.Length; i++)
{
Console.Write("{0} ", comb[i]);
p = p ^ data[comb[i]];
}
Console.WriteLine(" #[{0:X}]", p);
return p;
}
static uint[] data32;
static void Main(string[] args)
{
int n = 128;
int k = 6;
uint p = 0;
uint inv = 0;
long t = 0;
//load n numbers from a file
init(n);
var lookup1x = new Dictionary<uint, List<byte>>();
var lookup0x = new Dictionary<uint, List<byte>>();
Stopwatch watch = new Stopwatch();
watch.Start();
//do not use IEnumerable generator, use function directly to reuse xor value
var hash = new uint[k];
var comb = new int[k];
var stack = new Stack<int>();
stack.Push(0);
while (stack.Count > 0)
{
var index = stack.Count - 1;
var value = stack.Pop();
if (index == 0)
{
p = 0;
Console.WriteLine("Start {0} sequence, combinations found: {1}",value,t);
}
else
{
//restore previous xor value
p = hash[index - 1];
}
while (value < n)
{
//xor and store
p = p ^ data32[value];
hash[index] = p;
//remember current state (combination)
comb[index++] = value++;
if (value < n)
{
stack.Push(value);
}
//combination filled to end
if (index == k)
{
//if xor have MSB set, put it to lookup table 1x
if ((p & 0x8000000) == 0x8000000)
{
lookup1x[p] = comb.Select(i => (byte)i).ToList();
inv = p ^ 0xFFFFFFFF;
if (lookup0x.ContainsKey(inv))
{
var full = lookup0x[inv].Union(lookup1x[p]).OrderBy(x=>x).ToArray();
if (full.Length == 12)
{
print32(full, data32);
}
}
}
else
{
//otherwise put it to lookup table 2, but skip all combinations which are started with 0
if (comb[0] != 0)
{
lookup0x[p] = comb.Select(i => (byte)i).ToList();
inv = p ^ 0xFFFFFFFF;
if (lookup1x.ContainsKey(inv))
{
var full = lookup0x[p].Union(lookup1x[inv]).OrderBy(x=>x).ToArray();
if (full.Length == 12)
{
print32(full, data32);
}
}
}
}
t++;
break;
}
}
}
Console.WriteLine("Check was done in {0} ms ", watch.ElapsedMilliseconds);
//end
}
I don't know why I am getting wrong bits when reading my byte. I have followed some indications found here, bit it is not working. I show you my code:
byte[] byte22And23 = _packet.ReadBytes(2);
DataFromGTAPackets.Packet8.ControlFlags.rightEngineSmoke = _packet.GetBit(byte22And23[0], 0);
DataFromGTAPackets.Packet8.ControlFlags.leftEngineSmoke = _packet.GetBit(byte22And23[0], 1);
DataFromGTAPackets.Packet8.ControlFlags.rightEngineFire = _packet.GetBit(byte22And23[0], 2);
DataFromGTAPackets.Packet8.ControlFlags.leftEngineFire = _packet.GetBit(byte22And23[0], 3);
DataFromGTAPackets.Packet8.ControlFlags.rightRotorFail = _packet.GetBit(byte22And23[0], 4);
DataFromGTAPackets.Packet8.ControlFlags.leftRotorFail = _packet.GetBit(byte22And23[0], 5);
etc...
public bool GetBit(byte b, int bitNumber)
{
bool bit = (b & (1 << bitNumber - 1)) != 0;
return bit;
}
My byte 22 has a value of 2, it is: 00000010. And my byte 23 has a value of 0. When I use this code to read byte 22, my 3rd variable (rightEngineFire) is getting "true" (1). It has no sense, it is wrong obviously. But I don't know what is wrong.
Thank you!
You GetBit method considers bit numbers to be 1...32, instead of being 0...31.
Simple test:
bool b1 = GetBit(1, 0); // false
bool b2 = GetBit(1, 1); // true
You should change the method to
public static bool GetBit(byte b, int bitNumber)
{
bool bit = (b & (1 << bitNumber)) != 0;
return bit;
}
Or you could write:
DataFromGTAPackets.Packet8.ControlFlags.rightEngineSmoke = _packet.GetBit(byte22And23[0], 1);
But in C-derived languages (and C# is a C-derived language) we count from 0, so the first solution is better (for me).
And as a sidenote:
1 << bitNumber - 1
is quite unreadable, because probably 9 out of 10 programmers don't know/don't remember that the expression means
1 << (bitNumber - 1)
because in the operator precedence table the - comes before the <<, so when you mix operators you should use (...) to make clear the priority.
The GetBit() implementation is wrong, you can check with the following test:
[TestMethod]
public void MyTestMethod()
{
var byte22And23 = new byte[] { 2, 0 };
var sb = new StringBuilder();
for (int i = 7; i >=0; i--)
{
var r = GetBit(byte22And23[0], i);
sb.Append((r) ? "1" : "0");
}
// result: 00000100
Assert.AreEqual("00000010", sb.ToString());
}
It looks like there is no need of -1 in GetBit() because you are indexing bits 0-based and not 1-based:
public bool GetBit(byte b, int bitNumber)
{
// no need of -1 here ------------ˇ
bool bit = (b & (1 << bitNumber - 1)) != 0;
return bit;
}
After the modification the tests runs green.
I got an unordered list of int. Between 80 to 140 items, value of each item is between 0 and 175.
I'm generating a list of that list, about 5 to 10 millions of them.
I need to process, as fast as possible, all unique ordered sequence (excluding duplicate).
The way I'm doing it right now is creating a hash of all value of a list and inserting it into a hashset.
two hot spot while profiling is the ToArray() HOTSPOT1 and Array.Sort() HOTSPOT2
is there a better way of doing that task or a better alternative to fix the 2 hotspots? speed is important.
small demo, I tried to replicate as much as possible
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Example
{
//some other properties
public int Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
var checkedUnlock = new HashSet<int>();
var data = FakeData();
foreach (List<Example> subList in data)
{
var hash = CalcHash(subList.Select(x => x.Id).ToArray()); // HOTPSOT1
var newHash = checkedUnlock.Add(hash);
if (newHash)
{
//do something
}
}
}
static int CalcHash(int[] value)
{
Array.Sort(value); // HOTPSOT2
int hash;
unchecked // https://stackoverflow.com/a/263416/40868
{
hash = (int)2166136261;
var i = value.Length;
while (i-- > 0)
hash = (hash * 16777619) ^ value[i];
}
return hash;
}
//don't look at this, this is just to fake data
static List<List<Example>> FakeData()
{
var data = new List<List<Example>>();
var jMax = 10; //normally between 80 and 140
var idMax = 25; //normally between 0 and 175
var rnd = new Random(42);
var ids = Enumerable.Range(0, idMax).ToArray();
for (int i = 0; i < 500000; ++i)
{
//force duplicate
if(i % 50000 == 0)
{
ids = Enumerable.Range(0, idMax).ToArray();
rnd = new Random(42);
}
for (int r = 0; r < idMax; ++r)
{
int randomIndex = rnd.Next(idMax);
int temp = ids[randomIndex];
ids[randomIndex] = ids[r];
ids[r] = temp;
}
var subList = new List<Example>();
data.Add(subList);
for (int j = 0; j < jMax; ++j)
{
subList.Add(new Example() { Id = ids[j] });
}
}
return data;
}
}
}
So you have an array that can contain up to 140 items, and all values are in the range 0 through 175. All values in the array are unique, and order doesn't matter. That is, the array [20, 90, 16] will be considered the same as [16, 20, 90].
Given that, you can represent a single array as a set of 175 bits. Better, you can create the set without having to sort the input array.
You represent a set in C# as a BitArray. To compute the hash code of your array, you create the set, and then you iterate over the set to get the hash code. It looks something like this:
private BitArray HashCalcSet = new BitArray(175);
int CalcHash(int[] a, int startIndex)
{
// construct the set
HashCalcSet.SetAll(false);
for (var i = startIndex; i < a.Length; ++i)
{
HashCalcSet[a[i]] = true;
}
// compute the hash
hash = (int)2166136261;
for (var i = 174; i >= 0; --i)
{
if (HashCalcSet[i])
{
hash = (hash * 16777619) ^ value[i];
}
}
return hash;
}
That eliminates the sorting as well as the ToArray. You have to loop over the BitArray a couple of times, but three passes over the BitArray is quite possibly faster than sorting.
One problem I see with your solution is in how you're using the HashSet. You have this code:
var hash = CalcHash(subList.Select(x => x.Id).ToArray()); // HOTPSOT1
var newHash = checkedUnlock.Add(hash);
if (newHash)
{
//do something
}
That code mistakenly assumes that if the hash codes for two arrays are equal, then the arrays are equal. You're generating a 32-bit hash code for a 175-bit quantity. There will definitely be hash collisions. You're going to end up saying that two of your arrays are identical, when they aren't.
If that is a concern to you, let me know and I can edit my answer to provide a solution.
Allowing for comparison
If you want the ability to compare items for equality, rather than just checking if their hash codes are the same, you need to create an object that has Equals and GetHashCode methods. You'll insert that object into your HashSet. The simplest of those objects would contain the BitArray I described above, and methods that operate on it. Something like:
class ArrayObject
{
private BitArray theBits;
private int hashCode;
public override bool Equals(object obj)
{
if (object == null || GetType() != obj.GetType())
{
return false;
}
ArrayObject other = (ArrayObject)obj;
// compare two BitArray objects
for (var i = 0; i < theBits.Length; ++i)
{
if (theBits[i] != other.theBits[i])
return false;
}
return true;
}
public override int GetHashCode()
{
return hashCode;
}
public ArrayObject(int hash, BitArray bits)
{
theBits = bits;
hashCode = hash;
}
}
The idea being that you construct the BitArray and the hash code in the method as described above (although you'll have to allocate a new BitArray for each call), and then create and return one of these ArrayObject instances.
Your HashSet becomes HashSet<ArrayObject>.
The above works, but it's a big of a memory hog. You could reduce the memory requirement by creating a class that contains just three long integers. Instead of using a BitArray, you manipulate the bits directly. You map the bits so that numbers 0 through 63 modify bits 0 through 63 in the first number. Numbers 64 through 127 correspond to bits 0 through 63 of the second number, etc. You don't have to save a separate hash code then, because it'd be easy to compute from the three longs, and equality comparison becomes a lot easier, too.
The class looks something like this. Understand, I haven't tested the code, but the idea should be sound.
class ArrayObject2
{
private long l1;
private long l2;
private long l3;
public ArrayObject2(int[] theArray)
{
for (int i = 0; i < theArray.Length; ++i)
{
var rem = theArray[i] % 63;
int bitVal = 1 << rem;
if (rem < 64) l1 |= bitVal;
else if (rem < 128) l2 |= bitVal;
else l3 |= bitVal;
}
}
public override bool Equals(object obj)
{
var other = obj as ArrayObject2;
if (other == null) return false;
return l1 == other.l1 && l2 == other.l2 && l3 == other.l3;
}
public override int GetHashCode()
{
// very simple, and not very good hash function.
return (int)l1;
}
}
As I commented in the code, the hash function there isn't great. It will work, but you can do better with a little research.
This approach has the advantage of using less memory than the BitArray or the Boolean array. It'll probably be slower than the array of bool. It might be faster than the BitArray code. But whatever the case, it'll keep you from making the mistaken assumption that identical hash codes equals identical arrays.
I think you can save some time by re-using one array of bigger size instead of allocating new array every time causing extra memory traffic and garbage collection.
That would require custom sorting implementation which knows that even though array can have 1000 items, for current run only first 80 items needs to be sorted (and same for hash). It looks quicksort operating on subrange of ids should work fine. Quick sample of idea (haven't tested in details)
int[] buffer = new int[1000];
foreach (List<Example> subList in data)
{
for (int i = 0; i < subList.Count; i++)
{
buffer[i] = subList[i].Id;
}
var hash = CalcHashEx(buffer, 0, subList.Count - 1);
var newHash = checkedUnlock.Add(hash);
if (newHash)
{
//do something
}
}
public static void QuickSort(int[] elements, int left, int right)
{
int i = left, j = right;
int pivot = elements[(left + right) / 2];
while (i <= j)
{
while (elements[i] < pivot)
{
i++;
}
while (elements[j] > pivot)
{
j--;
}
if (i <= j)
{
// Swap
int tmp = elements[i];
elements[i] = elements[j];
elements[j] = tmp;
i++;
j--;
}
}
if (left < j)
{
QuickSort(elements, left, j);
}
if (i < right)
{
QuickSort(elements, i, right);
}
}
static int CalcHashEx(int[] value, int startIndex, int endIndex)
{
QuickSort(value, startIndex, endIndex);
int hash;
unchecked // https://stackoverflow.com/a/263416/40868
{
hash = (int)2166136261;
var i = endIndex + 1;
while (i-- > 0)
hash = (hash * 16777619) ^ value[i];
}
return hash;
}
This version of CalcHash() will let you remove the .ToArray() and replaces the Array.Sort() with something different that can act on a sequence, rather than needing the entire set... so that's both hot spots.
static int CalcHash(IEnumerable<int> value)
{
value = value.OrderByDescending(i => i);
int hash;
unchecked // https://stackoverflow.com/a/263416/40868
{
hash = (int)2166136261;
foreach(var item in value)
{
hash = (hash * 16777619) ^ item;
}
}
return hash;
}
I'm not sure how OrderByDescending() will fare in comparison. I suspect it will be slower than Array.Sort(), but still be an over-all win because of eliminating ToArray()... but you'll need to run the profiler again to know for sure.
There may also be improvement you can get from eliminating or reducing branching, via .GroupBy(), and running the code on the .First() item in each group:
var groups = data.GroupBy(sub => CalcHash(sub.Select(x => x.Id)));
foreach(List<Example> subList in groups.Select(g => g.First()))
{
//do something
}
going to put this here since it make no sense to put it in a comment
so far what I have done is created an array of boolean and setting the index of the item to true when present and I replaced the CalcHash with;
unchecked
{
hash = (int)2166136261;
var i = theMaxLength;
while (i-- > 0)
if(testing[i]) //the array of boolean
{
hash = (hash * 16777619) ^ i;
testing[i] = false;
}
}
doing so I removed the ToArray() and the Array.Sort() completely, this solution is kind of built from the dlxeon/jim/joel answer
i dropped the runtime by about 20-25% which is great
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
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.
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;
}
You can do this quite easily:
Math.Log(Math.Abs(a-b), 2)
Update: fixed...
If you can count from zero, then Math.Log(a^b,2) does the job
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.
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.
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.
Consider this:
[Flags]
enum Colors
{
Red=1,
Green=2,
Blue=4
}
Colors myColor=Colors.Red|Colors.Blue;
Currently, I'm doing it as follows:
int length=myColors.ToString().Split(new char[]{','}).Length;
But I hope there is a more efficient way of finding the length, maybe based on bitset operations.
Please, if possible, provide explanation why and how your solution works.
Also, if this a duplicate, please point to it and I'll delete this question. The only similar questions on SO I've been able to find were concerned about finding the length of all possible combinations of Colors enum, but not of the myColors variable.
UPDATE: I carefully benchmarked every solution (1 000 000 iterations each) and here is the results:
Stevo3000 - 8ms
MattEvans - 10ms
Silky - 34ms
Luke - 1757ms
Guffa - 4226ms
Tomas Levesque - 32810ms
The Stevo3000 is a clear winner (with Matt Evans holding silver medal).
Thank you very much for your help.
UPDATE 2:
This solution runs even faster: 41 ms for 100 000 000 iterations (roughly 40 times faster (32bit OS) than Stevo3000)
UInt32 v = (UInt32)co;
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
UInt32 count = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
The following code will give you the number of bits that are set for a given number of any type varying in size from byte up to long.
public static int GetSetBitCount(long lValue)
{
int iCount = 0;
//Loop the value while there are still bits
while (lValue != 0)
{
//Remove the end bit
lValue = lValue & (lValue - 1);
//Increment the count
iCount++;
}
//Return the count
return iCount;
}
This code is very efficient as it only iterates once for each bit rather than once for every possible bit as in the other examples.
Here are a few extension methods to manipulate Flags enumerations :
public static class EnumExtensions
{
private static void CheckEnumWithFlags<T>()
{
if (!typeof(T).IsEnum)
throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName));
if (!Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)))
throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName));
}
public static bool IsFlagSet<T>(this T value, T flag) where T : struct
{
CheckEnumWithFlags<T>();
long lValue = Convert.ToInt64(value);
long lFlag = Convert.ToInt64(flag);
return (lValue & lFlag) != 0;
}
public static IEnumerable<T> GetFlags<T>(this T value) where T : struct
{
CheckEnumWithFlags<T>();
foreach (T flag in Enum.GetValues(typeof(T)).Cast<T>())
{
if (value.IsFlagSet(flag))
yield return flag;
}
}
public static T SetFlags<T>(this T value, T flags, bool on) where T : struct
{
CheckEnumWithFlags<T>();
long lValue = Convert.ToInt64(value);
long lFlag = Convert.ToInt64(flags);
if (on)
{
lValue |= lFlag;
}
else
{
lValue &= (~lFlag);
}
return (T)Enum.ToObject(typeof(T), lValue);
}
public static T SetFlags<T>(this T value, T flags) where T : struct
{
return value.SetFlags(flags, true);
}
public static T ClearFlags<T>(this T value, T flags) where T : struct
{
return value.SetFlags(flags, false);
}
public static T CombineFlags<T>(this IEnumerable<T> flags) where T : struct
{
CheckEnumWithFlags<T>();
long lValue = 0;
foreach (T flag in flags)
{
long lFlag = Convert.ToInt64(flag);
lValue |= lFlag;
}
return (T)Enum.ToObject(typeof(T), lValue);
}
}
In your case you can use the GetFlags method :
int count = myColors.GetFlags().Count();
It's probably not as efficient as Luke's answer, but it's easier to use...
Here's my take on this... it counts the number of set bits in the value
int val = (int)myColor;
int count = 0;
while (val > 0)
{
if((val & 1) != 0)
{
count++;
}
val = val >> 1;
}
Here's a reasonably easy way of counting the bits. Each bit is shifted in-turn to the LSB of an Int64 which is AND-ed with 1 (to mask out any of the other bits) and then added to the running total.
int length = Enumerable.Range(0, 64).Sum(x => ((long)myColor >> x) & 1);
A rough approximation will be just counting the number of bits set in myColors, but that will only work if every enumeration members' value is power of 2.
Assuming they are flags, you can just use one of the methods here, to count the number of bits set.
It works because, as long as they are flags, when each one is 'OR'd' on, it sets one bit.
-- Edit
Sample code using one of the methods on that link:
[Flags]
enum Test
{
F1 = 1,
F2 = 2,
F3 = 4
}
class Program
{
static void Main(string[] args)
{
int v = (int) (Test.F1 | Test.F2 | Test.F3); // count bits set in this (32-bit value)
int c = 0; // store the total here
int[] S = {1, 2, 4, 8, 16}; // Magic Binary Numbers
int[] B = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF};
c = v - ((v >> 1) & B[0]);
c = ((c >> S[1]) & B[1]) + (c & B[1]);
c = ((c >> S[2]) + c) & B[2];
c = ((c >> S[3]) + c) & B[3];
c = ((c >> S[4]) + c) & B[4];
Console.WriteLine(c);
Console.Read();
}
}
I've made a helper method for myself. Maybe it'll be useful for others.
public static class EnumHelper
{
public static UInt32 NumFlags(this Enum e)
{
UInt32 v = Convert.ToUInt32(e);
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
UInt32 count = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
return count;
}
}
The solution that is most reliable is to test for each value in the enumeration:
int len = 0;
foreach (Colors color in Enum.GetValues(typeof(Colors))) {
if ((myColor & color) == color) {
len++;
}
}
This will work even if the value has bits set where there are no defined value in the enumeration, for example:
Colors myColor = (Colors)65535;
This will also work for enumerations with values that use more than a single bit:
[Flags]
enum Colors {
Red = 0xFF0000,
Green = 0x00FF00,
Blue = 0x0000FF
}
int value = Enum.GetNames(typeof(Colors)).Length;
public static int NumberOfOptions(int value)
{
int result = (int)Math.Pow(2, value-1);
return result;
}
Try this...
Colors.GetValues().Length();
...or is that too obvious?
EDIT:
OK, I just read the question again, and realised that you need the length of 'mycolors', not 'Colors' - let me think about that.
FURTHER EDIT:
Now I'm confused - the OP's posted solution would never work, as myColor.ToString() returns '5' and applying Split(new char[]{','}) to this would result in a array with a length of 1.
Did the OP actually get this to work?