I'm writing a time-critical piece of code in C# that requires me to convert two unsigned integers that define an inclusive range into a bit field. Ex:
uint x1 = 3;
uint x2 = 9;
//defines the range [3-9]
// 98 7654 3
//must be converted to: 0000 0011 1111 1000
It may help to visualize the bits in reverse order
The maximum value for this range is a parameter given at run-time which we'll call max_val. Therefore, the bit field variable ought to be defined as a UInt32 array with size equal to max_val/32:
UInt32 MAX_DIV_32 = max_val / 32;
UInt32[] bitArray = new UInt32[MAX_DIV_32];
Given a range defined by the variables x1 and x2, what is the fastest way to perform this conversion?
Try this. Calculate the range of array items that must be filled with all ones and do this by iterating over this range. Finally set the items at both borders.
Int32 startIndex = x1 >> 5;
Int32 endIndex = x2 >> 5;
bitArray[startIndex] = UInt32.MaxValue << (x1 & 31);
for (Int32 i = startIndex + 1; i <= endIndex; i++)
{
bitArray[i] = UInt32.MaxValue;
}
bitArray[endIndex] &= UInt32.MaxValue >> (31 - (x2 & 31));
May be the code is not 100% correct, but the idea should work.
Just tested it and found three bugs. The calculation at start index required a mod 32 and at end index the 32 must be 31 and a logical and instead of a assignment to handle the case of start and end index being the same. Should be quite fast.
Just benchmarked it with equal distribution of x1 and x2 over the array.
Intel Core 2 Duo E8400 3.0 GHz, MS VirtualPC with Server 2003 R2 on Windows XP host.
Array length [bits] 320 160 64
Performance [executions/s] 33 million 43 million 54 million
One more optimazation x % 32 == x & 31 but I am unable to meassure a performance gain. Because of only 10.000.000 iterations in my test the fluctuations are quite high. And I am running in VirtualPC making the situation even more unpredictable.
My solution for setting a whole range of bits in a BitArray to true or false:
public static BitArray SetRange(BitArray bitArray, Int32 offset, Int32 length, Boolean value)
{
Int32[] ints = new Int32[(bitArray.Count >> 5) + 1];
bitArray.CopyTo(ints, 0);
var firstInt = offset >> 5;
var lastInt = (offset + length) >> 5;
Int32 mask = 0;
if (value)
{
// set first and last int
mask = (-1 << (offset & 31));
if (lastInt != firstInt)
ints[lastInt] |= ~(-1 << ((offset + length) & 31));
else
mask &= ~(-1 << ((offset + length) & 31));
ints[firstInt] |= mask;
// set all ints in between
for (Int32 i = firstInt + 1; i < lastInt; i++)
ints[i] = -1;
}
else
{
// set first and last int
mask = ~(-1 << (offset & 31));
if (lastInt != firstInt)
ints[lastInt] &= -1 << ((offset + length) & 31);
else
mask |= -1 << ((offset + length) & 31);
ints[firstInt] &= mask;
// set all ints in between
for (Int32 i = firstInt + 1; i < lastInt; i++)
ints[i] = 0;
}
return new BitArray(ints) { Length = bitArray.Length };
}
You could try:
UInt32 x1 = 3;
UInt32 x2 = 9;
UInt32 newInteger = (UInt32)(Math.Pow(2, x2 + 1) - 1) &
~(UInt32)(Math.Pow(2, x1)-1);
Is there a reason not to use the System.Collections.BitArray class instead of a UInt32[]? Otherwise, I'd try something like this:
int minIndex = (int)x1/32;
int maxIndex = (int)x2/32;
// first handle the all zero regions and the all one region (if any)
for (int i = 0; i < minIndex; i++) {
bitArray[i] = 0;
}
for (int i = minIndex + 1; i < maxIndex; i++) {
bitArray[i] = UInt32.MaxValue; // set to all 1s
}
for (int i = maxIndex + 1; i < MAX_DIV_32; i++) {
bitArray[i] = 0;
}
// now handle the tricky parts
uint maxBits = (2u << ((int)x2 - 32 * maxIndex)) - 1; // set to 1s up to max
uint minBits = ~((1u << ((int)x1 - 32 * minIndex)) - 1); // set to 1s after min
if (minIndex == maxIndex) {
bitArray[minIndex] = maxBits & minBits;
}
else {
bitArray[minIndex] = minBits;
bitArray[maxIndex] = maxBits;
}
I was bored enough to try doing it with a char array and using Convert.ToUInt32(string, int) to convert to a uint from base 2.
uint Range(int l, int h)
{
char[] buffer = new char[h];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = i < h - l ? '1' : '0';
}
return Convert.ToUInt32(new string(buffer), 2);
}
A simple benchmark shows that my method is about 5% faster than Angrey Jim's (even if you replace second Pow with a bit shift.)
It is probably the easiest to convert to producing a uint array if the upper bound is too big to fit into a single int. It's a little cryptic but I believe it works.
uint[] Range(int l, int h)
{
char[] buffer = new char[h];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = i < h - l ? '1' : '0';
}
int bitsInUInt = sizeof(uint) * 8;
int numNeededUInts = (int)Math.Ceiling((decimal)buffer.Length /
(decimal)bitsInUInt);
uint[] uints = new uint[numNeededUInts];
for (int j = uints.Length - 1, s = buffer.Length - bitsInUInt;
j >= 0 && s >= 0;
j--, s -= bitsInUInt)
{
uints[j] = Convert.ToUInt32(new string(buffer, s, bitsInUInt), 2);
}
int remainder = buffer.Length % bitsInUInt;
if (remainder > 0)
{
uints[0] = Convert.ToUInt32(new string(buffer, 0, remainder), 2);
}
return uints;
}
Try this:
uint x1 = 3;
uint x2 = 9;
int cbToShift = x2 - x1; // 6
int nResult = ((1 << cbToShift) - 1) << x1;
/*
(1<<6)-1 gives you 63 = 111111, then you shift it on 3 bits left
*/
Related
I have a temperature sensor returning 2 bytes.
The temperature is defined as follows :
What is the best way in C# to convert these 2 byte to a float ?
My sollution is the following, but I don't like the power of 2 and the for loop :
static void Main(string[] args)
{
byte[] sensorData = new byte[] { 0b11000010, 0b10000001 }; //(-1) * (2^(6) + 2^(1) + 2^(-1) + 2^(-8)) = -66.50390625
Console.WriteLine(ByteArrayToTemp(sensorData));
}
static double ByteArrayToTemp(byte[] data)
{
// Convert byte array to short to be able to shift it
if (BitConverter.IsLittleEndian)
Array.Reverse(data);
Int16 dataInt16 = BitConverter.ToInt16(data, 0);
double temp = 0;
for (int i = 0; i < 15; i++)
{
//We take the LSB of the data and multiply it by the corresponding second power (from -8 to 6)
//Then we shift the data for the next loop
temp += (dataInt16 & 0x01) * Math.Pow(2, -8 + i);
dataInt16 >>= 1;
}
if ((dataInt16 & 0x01) == 1) temp *= -1; //Sign bit
return temp;
}
This might be slightly more efficient, but I can't see it making much difference:
static double ByteArrayToTemp(byte[] data)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(data);
ushort bits = BitConverter.ToUInt16(data, 0);
double scale = 1 << 6;
double result = 0;
for (int i = 0, bit = 1 << 14; i < 15; ++i, bit >>= 1, scale /= 2)
{
if ((bits & bit) != 0)
result += scale;
}
if ((bits & 0x8000) != 0)
result = -result;
return result;
}
You're not going to be able to avoid a loop when calculating this.
I'm getting the following errors when I try to rebuild a .dll
Please advise what can I replace these lines with so that the code will compile.
Background info (likely not relevant):
The .dll is part of an add-in output module for a program that controls Christmas lights. It outputs data from the program to the selected serial port telling the connected relay board which relays are to be on or off.
I intend to modify the output to suit my device so instead of the output being FF FF FF 00 00 00 00 00 for relay 1 2 3 on and 4 5 6 7 8 off it will send the appropriate format for the board That I have. (see below)
http://www.tinyosshop.com/image/data/board_modules/usbrelay4-5.jpg
Error CS0571 'SerialSetupDialog.SelectedPort.get': cannot explicitly call operator or accessor
It references the line in this section:
private void buttonSerialSetup_Click(object sender, EventArgs e)
{
SerialSetupDialog serialSetupDialog = new SerialSetupDialog(this.m_selectedPort);
if (((Form) serialSetupDialog).ShowDialog() != DialogResult.OK)
return;
this.m_selectedPort = serialSetupDialog.get_SelectedPort();
}
Also there are 3 cases of:
Error CS0221 Constant value '-128' cannot be converted to a 'byte' (use 'unchecked' syntax to override)
The compiler doesn't like this part of the code. "(byte) sbyte.MinValue;"
private void Protocol1Event(byte[] channelValues)
{
int length1 = channelValues.Length;
int count = 2;
int length2 = 2 + 2 * length1 + (2 + 2 * length1) / 100;
if (this.m_p1Packet.Length < length2)
this.m_p1Packet = new byte[length2];
this.m_p1Packet[0] = (byte) 126;
this.m_p1Packet[1] = (byte) sbyte.MinValue;
this.m_threadPosition = 10;
for (int index = 0; index < length1; ++index)
{
if ((int) channelValues[index] == 125)
{
this.m_threadPosition = 11;
this.m_p1Packet[count++] = (byte) 124;
}
else if ((int) channelValues[index] == 126)
{
this.m_threadPosition = 12;
this.m_p1Packet[count++] = (byte) 124;
}
else if ((int) channelValues[index] == (int) sbyte.MaxValue)
{
this.m_threadPosition = 13;
this.m_p1Packet[count++] = (byte) sbyte.MinValue;
}
else
{
this.m_threadPosition = 14;
this.m_p1Packet[count++] = channelValues[index];
}
if (count % 100 == 0)
{
this.m_threadPosition = 15;
this.m_p1Packet[count++] = (byte) 125;
}
this.m_threadPosition = 16;
}
this.m_threadPosition = 17;
if (this.m_running)
{
while (this.m_selectedPort.WriteBufferSize - this.m_selectedPort.BytesToWrite <= count)
Thread.Sleep(10);
this.m_threadPosition = 18;
this.m_selectedPort.Write(this.m_p1Packet, 0, count);
this.m_threadPosition = 19;
}
this.m_threadPosition = 20;
}
private void Protocol2Event(byte[] channelValues)
{
byte num1 = (byte) sbyte.MinValue;
int length = channelValues.Length;
byte[] array = new byte[8];
int num2 = 0;
while (num2 < length)
{
int num3 = Math.Min(num2 + 7, length - 1);
this.m_p2Packet[1] = num1++;
if (num3 >= length - 1)
this.m_p2Zeroes.CopyTo((Array) this.m_p2Packet, 3);
Array.Clear((Array) array, 0, 8);
for (int index = num2; index <= num3; ++index)
{
byte num4 = channelValues[index];
byte num5 = num4;
if ((int) num4 >= 1 && (int) num4 <= 8)
array[(int) num4 - 1] = (byte) 1;
else if ((int) num5 >= 1 && (int) num5 <= 8)
array[(int) num5 - 1] = (byte) 1;
}
byte num6 = (byte) (1 + Array.IndexOf<byte>(array, (byte) 0));
this.m_p2Packet[2] = num6;
int index1 = num2;
int count = 3;
while (index1 <= num3)
{
this.m_p2Packet[count] = (byte) ((uint) channelValues[index1] - (uint) num6);
++index1;
++count;
}
if (this.m_running)
this.m_selectedPort.Write(this.m_p2Packet, 0, count);
num2 += 8;
}
}
The reason that (byte)sbyte.MinValue; throws an error is because sbytes minimal value is -128 whereas bytes minimal value is 0. Therefore converting that to the other will cause an overflow. If you really want this behaviour you can use the keyword unchecked as the following:
byte b = unchecked((byte)sbyte.MinValue);
However this will give b the value of 128.
To answer the other part of your question I believe that replacing:
serialSetupDialog.get_SelectedPort();
with:
serialSetupDialog.SelectedPort;
should fix the issue.
is there a way to Ror an entire byte[] by a specific amount?
I've already done some research and found a solution to Rol a byte[] :
public static byte[] ROL_ByteArray(byte[] arr, int nShift)
{
//Performs bitwise circular shift of 'arr' by 'nShift' bits to the left
//RETURN:
// = Result
byte[] resArr = new byte[arr.Length];
if(arr.Length > 0)
{
int nByteShift = nShift / (sizeof(byte) * 8); //Adjusted after #dasblinkenlight's correction
int nBitShift = nShift % (sizeof(byte) * 8);
if (nByteShift >= arr.Length)
nByteShift %= arr.Length;
int s = arr.Length - 1;
int d = s - nByteShift;
for (int nCnt = 0; nCnt < arr.Length; nCnt++, d--, s--)
{
while (d < 0)
d += arr.Length;
while (s < 0)
s += arr.Length;
byte byteS = arr[s];
resArr[d] |= (byte)(byteS << nBitShift);
resArr[d > 0 ? d - 1 : resArr.Length - 1] |= (byte)(byteS >> (sizeof(byte) * 8 - nBitShift));
}
}
return resArr;
}
The author of this code can be found here: Is there a function to do circular bitshift for a byte array in C#?
Any idea how I can do the same thing but perform a Ror operation instead of a Rol operation on a byte[] ?
static byte[] ROR_ByteArray(byte[] arr, int nShift)
{
return ROL_ByteArray(arr, arr.Length*8-nShift);
}
I can't seem to find if there's a built-in way to do a circular bitshift of a byte array, what C's ROL and ROR used to do with a single byte?
Let me explain, say, I have an array (in binary):
[0] = 11001110
[1] = 01000100
[2] = 10100001
and then if I want to do ROL_Array(1 bit) or move bits 1 bit to the left, I'd get:
[0] = 10011100
[1] = 10001001
[2] = 01000011
or, if I want to do ROR_Array(2 bits) or move bits 2 bits to the right, I'd get:
[0] = 00110011
[1] = 01010001
[2] = 10101000
This is not as simple as you'd think. Here's a quick version before this thread gets closed:
public static byte[] ROL_ByteArray(byte[] arr, int nShift)
{
//Performs bitwise circular shift of 'arr' by 'nShift' bits to the left
//RETURN:
// = Result
byte[] resArr = new byte[arr.Length];
if(arr.Length > 0)
{
int nByteShift = nShift / (sizeof(byte) * 8); //Adjusted after #dasblinkenlight's correction
int nBitShift = nShift % (sizeof(byte) * 8);
if (nByteShift >= arr.Length)
nByteShift %= arr.Length;
int s = arr.Length - 1;
int d = s - nByteShift;
for (int nCnt = 0; nCnt < arr.Length; nCnt++, d--, s--)
{
while (d < 0)
d += arr.Length;
while (s < 0)
s += arr.Length;
byte byteS = arr[s];
resArr[d] |= (byte)(byteS << nBitShift);
resArr[d > 0 ? d - 1 : resArr.Length - 1] |= (byte)(byteS >> (sizeof(byte) * 8 - nBitShift));
}
}
return resArr;
}
and here's a test:
byte[] arr = new byte[] {
Convert.ToByte("11001110", 2),
Convert.ToByte("01000100", 2),
Convert.ToByte("10100001", 2),
};
byte[] arr2 = Auth.ROL_ByteArray(arr, 1);
string sss = "";
for (int i = 0; i < arr2.Length; i++)
sss += Convert.ToString(arr2[i], 2) + ", ";
Debug.WriteLine(sss);
Hello quick question regarding bit shifting
I have a value in HEX: new byte[] { 0x56, 0xAF };
which is 0101 0110 1010 1111
I want to the first N bits, for example 12.
Then I must right-shift off the lowest 4 bits (16 - 12) to get 0000 0101 0110 1010 (1386 dec).
I can't wrap my head around it and make it scalable for n bits.
Sometime ago i coded these two functions, the first one shifts an byte[] a specified amount of bits to the left, the second does the same to the right:
Left Shift:
public byte[] ShiftLeft(byte[] value, int bitcount)
{
byte[] temp = new byte[value.Length];
if (bitcount >= 8)
{
Array.Copy(value, bitcount / 8, temp, 0, temp.Length - (bitcount / 8));
}
else
{
Array.Copy(value, temp, temp.Length);
}
if (bitcount % 8 != 0)
{
for (int i = 0; i < temp.Length; i++)
{
temp[i] <<= bitcount % 8;
if (i < temp.Length - 1)
{
temp[i] |= (byte)(temp[i + 1] >> 8 - bitcount % 8);
}
}
}
return temp;
}
Right Shift:
public byte[] ShiftRight(byte[] value, int bitcount)
{
byte[] temp = new byte[value.Length];
if (bitcount >= 8)
{
Array.Copy(value, 0, temp, bitcount / 8, temp.Length - (bitcount / 8));
}
else
{
Array.Copy(value, temp, temp.Length);
}
if (bitcount % 8 != 0)
{
for (int i = temp.Length - 1; i >= 0; i--)
{
temp[i] >>= bitcount % 8;
if (i > 0)
{
temp[i] |= (byte)(temp[i - 1] << 8 - bitcount % 8);
}
}
}
return temp;
}
If you need further explanation please comment on this, i will then edit my post for clarification...
You can use a BitArray and then easily copy each bit to the right, starting from the right.
http://msdn.microsoft.com/en-us/library/system.collections.bitarray_methods.aspx
you want something like...
var HEX = new byte[] {0x56, 0xAF};
var bits = new BitArray(HEX);
int bitstoShiftRight = 4;
for (int i = 0; i < bits.Length; i++)
{
bits[i] = i < (bits.Length - bitstoShiftRight) ? bits[i + bitstoShiftRight] : false;
}
bits.CopyTo(HEX, 0);
If you have k total bits, and you want the "first" (as in most significant) n bits, you can simply right shift k-n times. The last k-n bits will be removed, by sort of "falling" off the end, and the first n will be moved to the least significant side.
Answering using C-like notation, assuming bits_in_byte is the number of bits in a byte determined elsewhere:
int remove_bits_count= HEX.count*bits_in_byte - bits_to_keep;
int remove_bits_in_byte_count= remove_bits_count % bits_in_byte;
if (remove_bits_count > 0)
{
for (int iteration= 0; iteration<min(HEX.count, (bits_to_keep + bits_in_byte - 1)/bits_in_byte); ++iteration)
{
int write_index= HEX.count - iteration - 1;
int read_index_lo= write_index - remove_bits_count/bits_in_byte;
if (read_index_lo>=0)
{
int read_index_hi= read_index_lo - (remove_bits_count + bits_in_byte - 1)/bits_in_byte;
HEX[write_index]=
(HEX[read_index_lo] >> remove_bits_in_byte_count) |
(HEX[read_index_hi] << (bits_in_byte - remove_bits_in_byte_count));
}
else
{
HEX[write_index]= 0;
}
}
}
Assuming you are overwriting the original array, you basically take every byte you write to and figure out the bytes that it would get its shifted bits from. You go from the end of the array to the front to ensure you never overwrite data you will need to read.