C# Bitshift & Bitwise operation - c#

I am trying to find the faster approach for the following problem.
I have 2 int arrays representing bits, here an example of an 8 positions one
int[] intArray1 = new[] {1, 1, 1, 0, 1, 1, 0, 1};
int[] intArray2 = new[] {0, 1, 0, 0, 1, 0, 0, 1};
The number of bits in the arrays could be 8, 32, 64 and 64+
So I should be able to create an algorithm that handles any kind of input, shifts bits for each and applies logical operations between both arrays in the faster way possible.
After a bit of research, I thought of casting the int array to a bool array and create a BitArray using the bool array, because BitArray has a constructor that supports bools as bits and it has built-in bit-wise operations.
bool[] boolArray = intArray.Select(s => s.Equals(1)).ToArray();
BitArray bitArray = new BitArray(boolArray);
However it does not support built-in bit-shifting, it needs to be done iterating, loosing the whole performance point that I am trying to achieve.
I could use int32 and int64 but that solution will not work for sizes larger than 64 bits.
Kind Regards

Why not just use a BigInteger?
You can use this method to convert a string to a BigInteger:
public static BigInteger BinToDec(string value)
{
// BigInteger can be found in the System.Numerics dll
BigInteger res = 0;
// I'm totally skipping error handling here
foreach(char c in value)
{
res <<= 1;
res += c == '1' ? 1 : 0;
}
return res;
}
Or if you want to stick with your int array and convert that to a BigInteger:
public static BigInteger BitArrayToBigDecimal(int[] bitIntArr) {
// BigInteger can be found in the System.Numerics dll
BigInteger res = 0;
// I'm totally skipping error handling here
foreach(int i in bitIntArr) {
res <<= 1;
res += i == 1 ? 1 : 0;
}
return res;
}
You can bit shift them, too. Like this:
var foo = BinToDec("11101101");
BigInteger fooShifted = foo >> 4;
var bar = BitArrayToBigDecimal(new[] {1, 1, 1, 0, 1, 1, 0, 1});
BigInteger barShifted = bar >> 4;
Let me know if you have any questions.

Related

Convert BitArray to a small byte array

I've read the other posts on BitArray conversions and tried several myself but none seem to deliver the results I want.
My situation is as such, I have some c# code that controls an LED strip. To issue a single command to the strip I need at most 28 bits
1 bit for selecting between 2 led strips
6 for position (Max 48 addressable leds)
7 for color x3 (0-127 value for color)
Suppose I create a BitArray for that structure and as an example we populate it semi-randomly.
BitArray ba = new BitArray(28);
for(int i = 0 ;i < 28; i++)
{
if (i % 3 == 0)
ba.Set(i, true);
else
ba.Set(i, false);
}
Now I want to stick those 28 bits in 4 bytes (The last 4 bits can be a stop signal), and finally turn it into a String so I can send the string via USB to the LED strip.
All the methods I've tried convert each 1 and 0 as a literal char which is not the goal.
Is there a straightforward way to do this bit compacting in C#?
Well you could use BitArray.CopyTo:
byte[] bytes = new byte[4];
ba.CopyTo(bytes, 0);
Or:
int[] ints = new int[1];
ba.CopyTo(ints, 0);
It's not clear what you'd want the string representation to be though - you're dealing with naturally binary data rather than text data...
I wouldn't use a BitArray for this. Instead, I'd use a struct, and then pack that into an int when I need to:
struct Led
{
public readonly bool Strip;
public readonly byte Position;
public readonly byte Red;
public readonly byte Green;
public readonly byte Blue;
public Led(bool strip, byte pos, byte r, byte g, byte b)
{
// set private fields
}
public int ToInt()
{
const int StripBit = 0x01000000;
const int PositionMask = 0x3F; // 6 bits
// bits 21 through 26
const int PositionShift = 20;
const int ColorMask = 0x7F;
const int RedShift = 14;
const int GreenShift = 7;
int val = Strip ? 0 : StripBit;
val = val | ((Position & PositionMask) << PositionShift);
val = val | ((Red & ColorMask) << RedShift);
val = val | (Blue & ColorMask);
return val;
}
}
That way you can create your structures easily without having to fiddle with bit arrays:
var blue17 = new Led(true, 17, 0, 0, 127);
var blah22 = new Led(false, 22, 15, 97, 42);
and to get the values:
int blue17_value = blue17.ToInt();
You can turn the int into a byte array easily enough with BitConverter:
var blue17_bytes = BitConverter.GetBytes(blue17_value);
It's unclear to me why you want to send that as a string.

convert byte array to uint numeric value

Let's say I have array of bytes
byte[] byteArr = new byte[] { 1, 2, 3, 4, 5 };
I want to convert this array to get regular numeric variable of uint, so result will be
uint result = 12345;
So far all the example I've seen were with bytes, byte I don't need bytes, but numeric value.
Thanks...
It sounds like you want something like:
uint result = 0;
foreach (var digit in array)
{
result = result * 10 + digit;
}
Or more fancily, using LINQ:
uint result = array.Aggregate((uint) 0, (curr, digit) => curr * 10 + digit);

Combine one Byte[] to Single Array

i do have an byte array included a range of numbers...
t Block and not the rest!
How can i have all block 4-8 in Temp[] ??
Elements 4-8 (or in reality index 3-7) is 5 bytes. Not 4.
You have the source offset and count mixed up:
Buffer.BlockCopy(bResponse, 3, temp, 0, 5);
Now temp will contain [23232].
If you want the last 4 bytes then use this:
Buffer.BlockCopy(bResponse, 4, temp, 0, 4);
Now temp will contain [3232].
To convert this to an int:
if (BitConverter.IsLittleEndian)
Array.Reverse(temp);
int i = BitConverter.ToInt32(temp, 0);
Edit: (After your comment that [43323232] actually is {43, 32, 32, 32})
var firstByte = temp[0]; // This is 43
var secondByte = temp[1]; // This is 32
var thirdByte = temp[2]; // 32
var fourthByte = temp[3]; // 32
If you want to convert this to an int then the BitConverter example above still works.

Convert int to a bit array in .NET

How can I convert an int to a bit array?
If I e.g. have an int with the value 3 I want an array, that has the length 8 and that looks like this:
0 0 0 0 0 0 1 1
Each of these numbers are in a separate slot in the array that have the size 8.
Use the BitArray class.
int value = 3;
BitArray b = new BitArray(new int[] { value });
If you want to get an array for the bits, you can use the BitArray.CopyTo method with a bool[] array.
bool[] bits = new bool[b.Count];
b.CopyTo(bits, 0);
Note that the bits will be stored from least significant to most significant, so you may wish to use Array.Reverse.
And finally, if you want get 0s and 1s for each bit instead of booleans (I'm using a byte to store each bit; less wasteful than an int):
byte[] bitValues = bits.Select(bit => (byte)(bit ? 1 : 0)).ToArray();
To convert the int 'x'
int x = 3;
One way, by manipulation on the int :
string s = Convert.ToString(x, 2); //Convert to binary in a string
int[] bits= s.PadLeft(8, '0') // Add 0's from left
.Select(c => int.Parse(c.ToString())) // convert each char to int
.ToArray(); // Convert IEnumerable from select to Array
Alternatively, by using the BitArray class-
BitArray b = new BitArray(new byte[] { x });
int[] bits = b.Cast<bool>().Select(bit => bit ? 1 : 0).ToArray();
Use Convert.ToString (value, 2)
so in your case
string binValue = Convert.ToString (3, 2);
I would achieve it in a one-liner as shown below:
using System;
using System.Collections;
namespace stackoverflowQuestions
{
class Program
{
static void Main(string[] args)
{
//get bit Array for number 20
var myBitArray = new BitArray(BitConverter.GetBytes(20));
}
}
}
Please note that every element of a BitArray is stored as bool as shown in below snapshot:
So below code works:
if (myBitArray[0] == false)
{
//this code block will execute
}
but below code doesn't compile at all:
if (myBitArray[0] == 0)
{
//some code
}
I just ran into an instance where...
int val = 2097152;
var arr = Convert.ToString(val, 2).ToArray();
var myVal = arr[21];
...did not produce the results I was looking for. In 'myVal' above, the value stored in the array in position 21 was '0'. It should have been a '1'. I'm not sure why I received an inaccurate value for this and it baffled me until I found another way in C# to convert an INT to a bit array:
int val = 2097152;
var arr = new BitArray(BitConverter.GetBytes(val));
var myVal = arr[21];
This produced the result 'true' as a boolean value for 'myVal'.
I realize this may not be the most efficient way to obtain this value, but it was very straight forward, simple, and readable.
To convert your integer input to an array of bool of any size, just use LINQ.
bool[] ToBits(int input, int numberOfBits) {
return Enumerable.Range(0, numberOfBits)
.Select(bitIndex => 1 << bitIndex)
.Select(bitMask => (input & bitMask) == bitMask)
.ToArray();
}
So to convert an integer to a bool array of up to 32 bits, simply use it like so:
bool[] bits = ToBits(65, 8); // true, false, false, false, false, false, true, false
You may wish to reverse the array depending on your needs.
Array.Reverse(bits);
int value = 3;
var array = Convert.ToString(value, 2).PadLeft(8, '0').ToArray();
public static bool[] Convert(int[] input, int length)
{
var ret = new bool[length];
var siz = sizeof(int) * 8;
var pow = 0;
var cur = 0;
for (var a = 0; a < input.Length && cur < length; ++a)
{
var inp = input[a];
pow = 1;
if (inp > 0)
{
for (var i = 0; i < siz && cur < length; ++i)
{
ret[cur++] = (inp & pow) == pow;
pow *= 2;
}
}
else
{
for (var i = 0; i < siz && cur < length; ++i)
{
ret[cur++] = (inp & pow) != pow;
pow *= 2;
}
}
}
return ret;
}
I recently discovered the C# Vector<T> class, which uses hardware acceleration (i.e. SIMD: Single-Instruction Multiple Data) to perform operations across the vector components as single instructions. In other words, it parallelizes array operations, to an extent.
Since you are trying to expand an integer bitmask to an array, perhaps you are trying to do something similar.
If you're at the point of unrolling your code, this would be an optimization to strongly consider. But also weigh this against the costs if you are only sparsely using them. And also consider the memory overhead, since Vectors really want to operate on contiguous memory (in CLR known as a Span<T>), so the kernel may be having to twiddle bits under the hood when you instantiate your own vectors from arrays.
Here is an example of how to do masking:
//given two vectors
Vector<int> data1 = new Vector<int>(new int[] { 1, 0, 1, 0, 1, 0, 1, 0 });
Vector<int> data2 = new Vector<int>(new int[] { 0, 1, 1, 0, 1, 0, 0, 1 });
//get the pairwise-matching elements
Vector<int> mask = Vector.Equals(data1, data2);
//and return values from another new vector for matches
Vector<int> whenMatched = new Vector<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8 });
//and zero otherwise
Vector<int> whenUnmatched = Vector<int>.Zero;
//perform the filtering
Vector<int> result = Vector.ConditionalSelect(mask, whenMatched, whenUnmatched);
//note that only the first half of vector components render in the Debugger (this is a known bug)
string resultStr = string.Join("", result);
//resultStr is <0, 0, 3, 4, 5, 6, 0, 0>
Note that the VS Debugger is bugged, showing only the first half of the components of a vector.
So with an integer as your mask, you might try:
int maskInt = 0x0F;//00001111 in binary
//convert int mask to a vector (anybody know a better way??)
Vector<int> maskVector = new Vector<int>(Enumerable.Range(0, Vector<int>.Count).Select(i => (maskInt & 1<<i) > 0 ? -1 : 0).ToArray());
Note that the (signed integer) -1 is used to signal true, which has binary representation of all ones.
Positive 1 does not work, and you can cast (int)-1 to uint to get every bit of the binary enabled, if needed (but not by using Enumerable.Cast<>()).
However this only works for int32 masks up to 2^8 because of the 8-element capacity in my system (that supports 4x64-bit chunks). This depends on the execution environment based on the hardware capabilities, so always use Vector<T>.Capacity.
You therefore can get double the capacity with shorts as ints as longs (the new Half type isn't yet supported, nor is "Decimal", which are the corresponding float/double types to int16 and int128):
ushort maskInt = 0b1111010101010101;
Vector<ushort> maskVector = new Vector<ushort>(Enumerable.Range(0, Vector<ushort>.Count).Select(i => (maskInt & 1<<i) > 0 ? -1 : 0).Select(x => (ushort)x).ToArray());
//string maskString = string.Join("", maskVector);//<65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 65535, 65535, 65535>
Vector<ushort> whenMatched = new Vector<ushort>(Enumerable.Range(1, Vector<ushort>.Count).Select(i => (ushort)i).ToArray());//{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
Vector<ushort> whenUnmatched = Vector<ushort>.Zero;
Vector<ushort> result = Vector.ConditionalSelect(maskVector, whenMatched, whenUnmatched);
string resultStr = string.Join("", result);//<1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 11, 0, 13, 14, 15, 16>
Due to how integers work, being signed or unsigned (using the most significant bit to indicate +/- values), you might need to consider that too, for values like converting 0b1111111111111111 to a short. The compiler will usually stop you if you try to do something that appears to be stupid, at least.
short maskInt = unchecked((short)(0b1111111111111111));
Just make sure you don't confuse the most-significant bit of an int32 as being 2^31.
Using & (AND)
Bitwise Operators
The answers above are all correct and effective. If you wanted to do it old-school, without using BitArray or String.Convert(), you would use bitwise operators.
The bitwise AND operator & takes two operands and returns a value where every bit is either 1, if both operands have a 1 in that place, or a 0 in every other case. It's just like the logical AND (&&), but it takes integral operands instead of boolean operands.
Ex. 0101 & 1001 = 0001
Using this principle, any integer AND the maximum value of that integer is itself.
byte b = 0b_0100_1011; // In base 10, 75.
Console.WriteLine(b & byte.MaxValue); // byte.MaxValue = 255
Result: 75
Bitwise AND in a loop
We can use this to our advantage to only take specific bits from an integer by using a loop that goes through every bit in a positive 32-bit integer (i.e., uint) and puts the result of the AND operation into an array of strings which will all be "1" or "0".
A number that has a 1 at only one specific digit n is equal to 2 to the nth power (I typically use the Math.Pow() method).
public static string[] GetBits(uint x) {
string[] bits = new string[32];
for (int i = 0; i < 32; i++) {
uint bit = x & Math.Pow(2, i);
if (bit == 1)
bits[i] = "1";
else
bits[i] = "0";
}
return bits;
}
If you were to input, say, 1000 (which is equivalent to binary 1111101000), you would get an array of 32 strings that would spell 0000 0000 0000 0000 0000 0011 1110 1000 (the spaces are just for readability).

How to write bits to a file?

How to write bits (not bytes) to a file with c#, .net? I'm preety stuck with it.
Edit: i'm looking for a different way that just writing every 8 bits as a byte
The smallest amount of data you can write at one time is a byte.
If you need to write individual bit-values. (Like for instance a binary format that requires a 1 bit flag, a 3 bit integer and a 4 bit integer); you would need to buffer the individual values in memory and write to the file when you have a whole byte to write. (For performance, it makes sense to buffer more and write larger chunks to the file).
Accumulate the bits in a buffer (a single byte can qualify as a "buffer")
When adding a bit, left-shift the buffer and put the new bit in the lowest position using OR
Once the buffer is full, append it to the file
I've made something like this to emulate a BitsWriter.
private BitArray bitBuffer = new BitArray(new byte[65536]);
private int bitCount = 0;
// Write one int. In my code, this is a byte
public void write(int b)
{
BitArray bA = new BitArray((byte)b);
int[] pattern = new int[8];
writeBitArray(bA);
}
// Write one bit. In my code, this is a binary value, and the amount of times
public void write(int b, int len)
{
int[] pattern = new int[len];
BitArray bA = new BitArray(len);
for (int i = 0; i < len; i++)
{
bA.Set(i, (b == 1));
}
writeBitArray(bA);
}
private void writeBitArray(BitArray bA)
{
for (int i = 0; i < bA.Length; i++)
{
bitBuffer.Set(bitCount + i, bA[i]);
bitCount++;
}
if (bitCount % 8 == 0)
{
BitArray bitBufferWithLength = new BitArray(new byte[bitCount / 8]);
byte[] res = new byte[bitBuffer.Count / 8];
for (int i = 0; i < bitCount; i++)
{
bitBufferWithLength.Set(i, (bitBuffer[i]));
}
bitBuffer.CopyTo(res, 0);
bitCount = 0;
base.BaseStream.Write(res, 0, res.Length);
}
}
You will have to use bitshifts or binary arithmetic, as you can only write one byte at a time, not individual bits.

Categories