Есть byte[]
Требуется выполнить для него битовый сдвиг влево или вправо с минимальными затратами.
В поиске решений я наткнулся на BitArray
. Один из его конструкторов принимает массив байт. Класс позволяет выполнять различные битовые операции (AND NOT OR XOR), но не позволяет делать сдвиги.
Можно было бы попробовать
return ((new System.Numerics.BigInteger(b)) << k).ToByteArray()
хотя потенциальные 3 копирования массива несколько настораживают.
Впрочем, можно заглянуть в его исходники и как-то использовать соответствующий код:
public static BigInteger operator <<(BigInteger value, int shift) {
if (shift == 0) return value;
else if (shift == Int32.MinValue) return ((value >> Int32.MaxValue) >> 1);
else if (shift < 0) return value >> -shift;
int digitShift = shift / kcbitUint;
int smallShift = shift - (digitShift * kcbitUint);
uint[] xd; int xl; bool negx;
negx = GetPartsForBitManipulation(ref value, out xd, out xl);
int zl = xl + digitShift + 1;
uint[] zd = new uint[zl];
if (smallShift == 0) {
for (int i = 0; i < xl; i++) {
zd[i + digitShift] = xd[i];
}
} else {
int carryShift = kcbitUint - smallShift;
uint carry = 0;
int i;
for (i = 0; i < xl; i++) {
uint rot = xd[i];
zd[i + digitShift] = rot << smallShift | carry;
carry = rot >> carryShift;
}
zd[i + digitShift] = carry;
}
return new BigInteger(zd, negx);
}
#region сдвиг на 1 бит
byte[] myBytes;
BitArray gamma_value = new BitArray(myBytes);
int len = gamma_value.Length; //длина массива бит
c = gamma_value[0]; //младший бит
//создание массива типа bool
//такой же длины как gamma_value типа BitArray
bool[] gamma_new = new bool[len];
//копируем массив типа BitArray в массив типа bool
gamma_value.CopyTo(gamma_new, 0);
//копируем массив bool со сдвигом на 1ну позицию в другой массив bool
Array.Copy(gamma_new, 1, gamma_new, 0, len - 1);
//преобразование массива типа bool в массив типа BitArray
gamma_value = new BitArray(gamma_new);
gamma_value.CopyTo(myBytes, 0); //переводим массив бит в массив байт
#endregion
Сдвиг придётся реализовывать алгоритимчески: требуется на основе величины сдвига в цикле определить в какой байт попадут данные из текущего байта. Данные байта делятся на две части: смещённая и смещаемая часть.
Задание решить несложно, но это требует времени. Советую разбить задачу на несколько частей, например: превратить любое отрицательное смещение в положительное; сделать переход по всем байтам в цикле; разбить байт на две части - та что выпала после смещения и вторая; в локальные переменные записать значения новых индексов и смещения в их байтах для данных текущего байта; записать в другой массив такой же длинны по смещённым индексам
/// <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;
}
Идея состоит в ручном копировании битов. То есть если делаем сдвиг влево на 4 бита, то копируем в 0-й бит 4-й бит, в 1-й - 5-й и т.д. Соответственно, в, например, 15-й бит (2-й байт) копируется 19-й бит (3-й байт).
Для сдвига вправо - аналогично.
private static readonly byte[] bits = new byte[] { 0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1 };
public static void ShiftLeft(byte[] array, int shift)
{
var totalLength = array.Length * 8;
for (var toIndex = 0; toIndex < totalLength; toIndex++)
{
var fromIndex = toIndex + shift;
SetBit(fromIndex, toIndex, array);
}
}
public static void ShiftRight(byte[] array, int shift)
{
var totalLength = array.Length * 8;
for (var toIndex = totalLength - 1; toIndex >= 0; toIndex--)
{
var fromIndex = toIndex - shift;
SetBit(fromIndex, toIndex, array);
}
}
private static void SetBit(int fromIndex, int toIndex, byte[] array)
{
var toBit = bits[toIndex % 8];
int toByte = array[toIndex / 8];
toByte &= ~toBit;
if (fromIndex >= 0 && fromIndex < array.Length * 8)
{
var fromByte = array[fromIndex / 8];
var fromBit = bits[fromIndex % 8];
if ((fromByte & fromBit) != 0)
{
toByte += toBit;
}
}
array[toIndex / 8] = (byte)toByte;
}
Не могу решить умножение матриц через форму, то есть надо задать размер двух матриц так же через форму, умножить и вывести на экран
Для установки KeepAlive опции я использую метод socketIOControl:
Имеется код, который должен завершать процесс, который был запущен из указанной папки:
У меня проблема с парсингом даты из строки в Datetime формат, когда я использую, напр01