I'm trying to write function that converts an arbitrary large array of bytes (larger than 64-bit) into a decimal number represented as string in c# and I simply can't figure out how to do it.
For example the following code ...
Console.WriteLine(ConvertToString(
new byte[]
{
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00
}));
.. should print out
22774453838368691933757882222884355840
I don't want to just use an extra library like biginteger for that, because I want it to be simple and like to understand how it works.
Some guidelines:
You will need to save the digits of the number in a matrix, one space for each digit. The matrix starts empty.
Then you need a matrix to save the multiplication of the matrix. It too starts empty.
Now for each byte you have:
First multiply each digit of the current number matrix by 256, save the 10 modulus in the corresponding temporary digit and add the the number divided by 10 to the next digits multiplication.
Assign the temporary multiplication matrix to the current digit matrix.
Then add the byte to the first digit.
Correct the current matrix, saving only the 10 modulus in each index and passing the value divided by 10 to the next index.
Then you need to concatenate each digit in a string.
Return the string.
Don't forget to expand each matrix as needed, or determine the maximum size needed from the number of bytes been passed.
Edit, example following the third step above:
Values = [0xAA, 0xBB]
Initial Current = []
Initial Temp = []
With 0xAA
Nothing to multiply.
No change on assignment.
We add 0xAA to the first value in current: Current = [170]
We correct current to save only the modulus, passing the value divided by ten to the next value:
1st digit: Current = [0] pass 17.
2nd digit: Current = [0, 7] pass 1.
3rd digit: Current = [0, 7, 1] no value to pass so process ends.
Now with 0xBB
Multipli by 256, save in temp and correct, do for each digit:
1st digit: Temp = [0], 0 to save to the next digit.
2nd digit: Temp = [0, 1792] before correction, Temp = [0, 2], 179 to pass after correction.
3rd digit: Temp = [0, 2, 1 * 256 + 179 = 435] before correction, Temp = [0, 2, 5], 43 to pass after correction.
4th digit: Temp = [0, 2, 5, 43] before, Temp = [0, 2, 5, 3], 3 to pass after
5th digit: Temp = [0, 2, 5, 3, 4] before and after correction, no digit to save, so the multiplication ends.
Assing temp to current: Current = [0, 2, 5, 3, 4]; Temp = []
Add the current value to the first digit: Current = [187, 2, 5, 3, 4]
Correct the values:
1st digit: Current = [7, 2, 5, 3, 4], 18 to pass.
2nd digit: Current = [7, 0, 5, 3, 4], 2 to pass.
3rd digit: Current = [7, 0, 7, 3, 4], nothing to pass so the addition ends.
Now we only need to concatenate for the result 43707.
Based on #Wilheim's answer:
static string BytesToString(byte[] data) {
// Minimum length 1.
if (data.Length == 0) return "0";
// length <= digits.Length.
var digits = new byte[(data.Length * 0x00026882/* (int)(Math.Log(2, 10) * 0x80000) */ + 0xFFFF) >> 16];
int length = 1;
// For each byte:
for (int j = 0; j != data.Length; ++j) {
// digits = digits * 256 + data[j].
int i, carry = data[j];
for (i = 0; i < length || carry != 0; ++i) {
int value = digits[i] * 256 + carry;
carry = Math.DivRem(value, 10, out value);
digits[i] = (byte)value;
}
// digits got longer.
if (i > length) length = i;
}
// Return string.
var result = new StringBuilder(length);
while (0 != length) result.Append((char)('0' + digits[--length]));
return result.ToString();
}
You want to understand the workings so take a look at super cool
C# BigInteger Class # CodeProject.
Also, I have stripped that class to bare essentials for this question. It can be optimized further. :)
Try copy and paste following code it works!!
using System;
public class BigInteger
{
// maximum length of the BigInteger in uint (4 bytes)
// change this to suit the required level of precision.
private const int maxLength = 70;
private uint[] data = null; // stores bytes from the Big Integer
public int dataLength; // number of actual chars used
public BigInteger()
{
data = new uint[maxLength];
dataLength = 1;
}
public BigInteger(long value)
{
data = new uint[maxLength];
long tempVal = value;
dataLength = 0;
while (value != 0 && dataLength < maxLength)
{
data[dataLength] = (uint)(value & 0xFFFFFFFF);
value >>= 32;
dataLength++;
}
if (tempVal > 0) // overflow check for +ve value
{
if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0)
throw (new ArithmeticException("Positive overflow in constructor."));
}
else if (tempVal < 0) // underflow check for -ve value
{
if (value != -1 || (data[dataLength - 1] & 0x80000000) == 0)
throw (new ArithmeticException("Negative underflow in constructor."));
}
if (dataLength == 0)
dataLength = 1;
}
public BigInteger(ulong value)
{
data = new uint[maxLength];
// copy bytes from ulong to BigInteger without any assumption of
// the length of the ulong datatype
dataLength = 0;
while (value != 0 && dataLength < maxLength)
{
data[dataLength] = (uint)(value & 0xFFFFFFFF);
value >>= 32;
dataLength++;
}
if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0)
throw (new ArithmeticException("Positive overflow in constructor."));
if (dataLength == 0)
dataLength = 1;
}
public BigInteger(BigInteger bi)
{
data = new uint[maxLength];
dataLength = bi.dataLength;
for (int i = 0; i < dataLength; i++)
data[i] = bi.data[i];
}
public BigInteger(byte[] inData)
{
dataLength = inData.Length >> 2;
int leftOver = inData.Length & 0x3;
if (leftOver != 0) // length not multiples of 4
dataLength++;
if (dataLength > maxLength)
throw (new ArithmeticException("Byte overflow in constructor."));
data = new uint[maxLength];
for (int i = inData.Length - 1, j = 0; i >= 3; i -= 4, j++)
{
data[j] = (uint)((inData[i - 3] << 24) + (inData[i - 2] << 16) +
(inData[i - 1] << 8) + inData[i]);
}
if (leftOver == 1)
data[dataLength - 1] = (uint)inData[0];
else if (leftOver == 2)
data[dataLength - 1] = (uint)((inData[0] << 8) + inData[1]);
else if (leftOver == 3)
data[dataLength - 1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]);
while (dataLength > 1 && data[dataLength - 1] == 0)
dataLength--;
//Console.WriteLine("Len = " + dataLength);
}
public override string ToString()
{
return ToString(10);
}
public string ToString(int radix)
{
string charSet = "ABCDEF";
string result = "";
BigInteger a = this;
BigInteger quotient = new BigInteger();
BigInteger remainder = new BigInteger();
BigInteger biRadix = new BigInteger(radix);
if (a.dataLength == 1 && a.data[0] == 0)
result = "0";
else
{
while (a.dataLength > 1 || (a.dataLength == 1 && a.data[0] != 0))
{
singleByteDivide(a, biRadix, quotient, remainder);
if (remainder.data[0] < 10)
result = remainder.data[0] + result;
else
result = charSet[(int)remainder.data[0] - 10] + result;
a = quotient;
}
}
return result;
}
private static void singleByteDivide(BigInteger bi1, BigInteger bi2,
BigInteger outQuotient, BigInteger outRemainder)
{
uint[] result = new uint[maxLength];
int resultPos = 0;
// copy dividend to reminder
for (int i = 0; i < maxLength; i++)
outRemainder.data[i] = bi1.data[i];
outRemainder.dataLength = bi1.dataLength;
while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0)
outRemainder.dataLength--;
ulong divisor = (ulong)bi2.data[0];
int pos = outRemainder.dataLength - 1;
ulong dividend = (ulong)outRemainder.data[pos];
if (dividend >= divisor)
{
ulong quotient = dividend / divisor;
result[resultPos++] = (uint)quotient;
outRemainder.data[pos] = (uint)(dividend % divisor);
}
pos--;
while (pos >= 0)
{
dividend = ((ulong)outRemainder.data[pos + 1] << 32) + (ulong)outRemainder.data[pos];
ulong quotient = dividend / divisor;
result[resultPos++] = (uint)quotient;
outRemainder.data[pos + 1] = 0;
outRemainder.data[pos--] = (uint)(dividend % divisor);
}
outQuotient.dataLength = resultPos;
int j = 0;
for (int i = outQuotient.dataLength - 1; i >= 0; i--, j++)
outQuotient.data[j] = result[i];
for (; j < maxLength; j++)
outQuotient.data[j] = 0;
while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0)
outQuotient.dataLength--;
if (outQuotient.dataLength == 0)
outQuotient.dataLength = 1;
while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0)
outRemainder.dataLength--;
}
public static void Main(string[] args)
{
BigInteger big = new BigInteger( new byte[]
{
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00
});
Console.WriteLine(big);
}
}
Would System.Decimal meet your needs?
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 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);
In C#, is there a way to right/left shift an entire byte array (and subsequently adding a byte to a particular side for the last bit isn't lost)?
I know this sounds like a weird request, but I'd still like to know if its possible and/or how to begin doing it.
Just for grins. shifting and rotating bytes in a byte array. (not bitshifting)
shift left, zero fill:
mybytes.Skip(1).Concat(new byte[] { 0 }).ToArray();
shift right, zero fill:
(new byte[] {0}).Concat(mybytes.Take(mybytes.Length - 1)).ToArray();
rotate left:
mybytes.Skip(1).Concat(mybytes.Take(1)).ToArray();
rotate right:
mybytes.Skip(mbytes.Length - 1).Concat(mbytes.Take(mbytes.Length - 1)).ToArray();
Yes, you can. See the following methods I wrote:
/// <summary>
/// Rotates the bits in an array of bytes to the left.
/// </summary>
/// <param name="bytes">The byte array to rotate.</param>
public static void RotateLeft(byte[] bytes)
{
bool carryFlag = ShiftLeft(bytes);
if (carryFlag == true)
{
bytes[bytes.Length - 1] = (byte)(bytes[bytes.Length - 1] | 0x01);
}
}
/// <summary>
/// Rotates the bits in an array of bytes to the right.
/// </summary>
/// <param name="bytes">The byte array to rotate.</param>
public static void RotateRight(byte[] bytes)
{
bool carryFlag = ShiftRight(bytes);
if (carryFlag == true)
{
bytes[0] = (byte)(bytes[0] | 0x80);
}
}
/// <summary>
/// Shifts the bits in an array of bytes to the left.
/// </summary>
/// <param name="bytes">The byte array to shift.</param>
public static bool ShiftLeft(byte[] bytes)
{
bool leftMostCarryFlag = false;
// Iterate through the elements of the array from left to right.
for (int index = 0; index < bytes.Length; index++)
{
// If the leftmost bit of the current byte is 1 then we have a carry.
bool carryFlag = (bytes[index] & 0x80) > 0;
if (index > 0)
{
if (carryFlag == true)
{
// Apply the carry to the rightmost bit of the current bytes neighbor to the left.
bytes[index - 1] = (byte)(bytes[index - 1] | 0x01);
}
}
else
{
leftMostCarryFlag = carryFlag;
}
bytes[index] = (byte)(bytes[index] << 1);
}
return leftMostCarryFlag;
}
/// <summary>
/// Shifts the bits in an array of bytes to the right.
/// </summary>
/// <param name="bytes">The byte array to shift.</param>
public static bool ShiftRight(byte[] bytes)
{
bool rightMostCarryFlag = false;
int rightEnd = bytes.Length - 1;
// Iterate through the elements of the array right to left.
for (int index = rightEnd; index >= 0; index--)
{
// If the rightmost bit of the current byte is 1 then we have a carry.
bool carryFlag = (bytes[index] & 0x01) > 0;
if (index < rightEnd)
{
if (carryFlag == true)
{
// Apply the carry to the leftmost bit of the current bytes neighbor to the right.
bytes[index + 1] = (byte)(bytes[index + 1] | 0x80);
}
}
else
{
rightMostCarryFlag = carryFlag;
}
bytes[index] = (byte)(bytes[index] >> 1);
}
return rightMostCarryFlag;
}
It seems you are performing bit operations on large amount of bits storing them in a byte array. Consider using BitArray class and BitVector32 Structure. Depending on what you are doing with bits you can create a class like this. Note that shifting works in O(1) instead of O(n).
public class BitRing : IEnumerable<bool>
{
private readonly BitArray m_InnerBitArray;
private int m_StarIndex;
public BitRing(byte[] bytes)
{
m_InnerBitArray = new BitArray(bytes);
m_StarIndex = 0;
}
public void ShiftLeft()
{
m_StarIndex++;
}
public void ShiftRight()
{
m_StarIndex--;
}
public bool this[int i]
{
get
{
int index = GetIndex(i);
return m_InnerBitArray[index];
}
set
{
int index = GetIndex(i);
m_InnerBitArray[index] = value;
}
}
private int GetIndex(int i)
{
return i - m_StarIndex%m_InnerBitArray.Count;
}
public IEnumerator<bool> GetEnumerator()
{
for (int i = m_StarIndex; i < m_InnerBitArray.Count; i++)
{
yield return m_InnerBitArray[i];
}
for (int i = 0; i < m_StarIndex; i++)
{
yield return m_InnerBitArray[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
I've given it some more thought and realized that this probably fits the question better:
public static void Main()
{
byte[] bytes = new byte[] { 0xFF, 0x01, 0x80, 0x81 };
Stack<bool> bitStack = CreateBitStack(bytes);
ShiftLeftExpand(bitStack, 1);
byte[] newBytes = CreateByteArray(bitStack);
}
public static void ShiftLeftExpand(Stack<bool> bitStack, int count)
{
while (count-- > 0)
{
bitStack.Push(false);
}
}
public static Stack<bool> CreateBitStack(byte[] bytes)
{
Stack<bool> bitStack = new Stack<bool>(bytes.Length * 8);
for (int bytePosition = 0; bytePosition < bytes.Length; bytePosition++)
{
for (int bitPosition = 7; bitPosition >= 0; bitPosition--)
{
int bitMask = 0x01 << bitPosition;
bitStack.Push((bytes[bytePosition] & bitMask) > 0);
}
}
return bitStack;
}
public static byte[] CreateByteArray(Stack<bool> bitStack)
{
int newArrayLength = (int)Math.Ceiling(bitStack.Count / 8.0);
byte[] bytes = new byte[newArrayLength];
int bitCounter = 0;
while (bitStack.Count > 0)
{
bool? bitValue = bitStack.Pop();
int bitPosition = bitCounter % 8;
int bytePosition = newArrayLength - 1 - bitCounter / 8;
if (bitValue == true)
{
bytes[bytePosition] = (byte)(bytes[bytePosition] | (0x01 << bitPosition));
}
bitCounter++;
}
return bytes;
}
A similar technique can be applied to perform the right shift.
Linq way:
static class Shifter
{
public static byte[] ShiftLeft(this byte[] array, int n)
{
var a = array.Select(x => (byte)(x >> 8 - n % 8)).Concat(new byte[(7 + n) / 8]).Select((x, i) => new Tuple<int, byte>(i - (n % 8 == 0 ? 0 : 1), x));
var b = array.Select(x => (byte)(x << n % 8)).Concat(new byte[n / 8]).Select((x, i) => new Tuple<int, byte>(i, x));
return (from x in a
join y in b on x.Item1 equals y.Item1 into yy
from y in yy.DefaultIfEmpty()
select (byte)(x.Item2 | (y == null ? 0 : y.Item2))).ToArray();
}
public static byte[] ShiftRight(this byte[] array, int n)
{
return (new byte[n/8]).Concat(ShiftLeft(array, (8 - (n%8))%8)).ToArray();
}
}
I don't think there's a built-in way. I implemented the shift-left operation you described below (assuming little endian). It's not quite as elegant as you can do with x86 assembly (shift with carry instructions), but pretty close to what you could do with C.
Alternately, you can almost use the BigInteger struct (.NET 4 and above) which has a constructor that takes a byte array and a ToByteArray method. But its shift left operation sign-extends the high byte and its shift right operation truncates. So you'd need to compensate for both to get the exact behavior you described.
// Left-shifts a byte array in place. Assumes little-endian. Throws on overflow.
static public void ShiftByteArrayLeft(byte[] array)
{
if (array == null)
throw new ArgumentNullException("array");
if (array[array.Length - 1] >= 0x80)
throw new OverflowException();
// move left-to-right, left-shifting each byte
for (int i = array.Length - 1; i >= 1; --i)
{
// left-shift current byte
array[i] <<= 1;
// carry the bit from the next/right byte if needed
if (array[i - 1] >= 0x80)
++array[i];
}
// finally shift the left-shift the right-most byte
array[0] <<= 1;
}
// Left-shifts a byte array in place. Assumes little-endian. Grows array as needed.
static public void ShiftByteArrayLeftAutoGrow(ref byte[] array)
{
if (array == null)
throw new ArgumentNullException("array");
if (array[array.Length - 1] >= 0x80)
{
// allocate a bigger array and do the left-shift on it
byte[] oldArray = array;
array = new byte[oldArray.Length + 1];
Array.Copy(oldArray, 0, array, 0, oldArray.Length);
}
ShiftByteArrayLeft(array);
}
Shift left:
for (int i = byteArray.Length - 1; i >= 0; i--) byteArray[i] = (byte)((byteArray[i] << 1) | ((i == 0) ? 0 : byteArray[i - 1] >> 7));
Shift right:
for (int i = 0; i <= byteArray.Length - 1; i++) byteArray[i] = (byte)((byteArray[i] >> 1) | ((i == byteArray.Length - 1) ? 0 : byteArray[i + 1] << 7));
These two functions will shift the bits in an array of bytes the specified amount, shifting them into neighboring bytes as needed. Optionally, they can wrap the bits from one end of the array to the other. Note that they create a new array, but the code can be easily changed to modify the passed 'array' instead...
public static byte[] ShiftRight(byte[] array, int shift, bool wrap = false) {
if(shift < 0) {
throw new ArgumentOutOfRangeException("shift");
} else if(shift == 0) {
return (byte[])array.Clone();
} else {
if(wrap) shift %= (array.Length * 8);
if(shift >= (array.Length * 8)) return new byte[array.Length];
var offset = (shift / 8);
shift %= 8;
var ʀ = new byte[array.Length];
for(var ɪ = 0; ɪ < ʀ.Length; ɪ++) {
var indexL_ɪ = (ɪ + offset);
var indexH_ɪ = (ɪ + offset + 1);
if(wrap) {
if(indexL_ɪ >= array.Length) indexL_ɪ -= array.Length;
if(indexH_ɪ >= array.Length) indexH_ɪ -= array.Length;
}
if(indexL_ɪ < array.Length) ʀ[ɪ] = (byte)(array[indexL_ɪ] >> shift);
if(indexH_ɪ < array.Length) ʀ[ɪ] |= (byte)(array[indexH_ɪ] << (8 - shift));
}
return ʀ;
}
}
public static byte[] ShiftLeft(byte[] array, int shift, bool wrap = false) {
if(shift < 0) {
throw new ArgumentOutOfRangeException("shift");
} else if(shift == 0) {
return (byte[])array.Clone();
} else {
if(wrap) shift %= (array.Length * 8);
if(shift >= (array.Length * 8)) return new byte[array.Length];
var offset = (shift / 8);
shift %= 8;
for(var ɪ = 0; ɪ < ʀ.Length; ɪ++) {
var indexL_ɪ = (ɪ - offset - 1);
var indexH_ɪ = (ɪ - offset);
if(wrap) {
if(indexL_ɪ < 0) indexL_ɪ += array.Length;
if(indexH_ɪ < 0) indexH_ɪ += array.Length;
}
if(indexL_ɪ >= 0) ʀ[ɪ] = (byte)(array[indexL_ɪ] >> (8 - shift));
if(indexH_ɪ >= 0) ʀ[ɪ] |= (byte)(array[indexH_ɪ] << shift);
}
return ʀ;
}
}
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.
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
*/