Должен быть более быстрый и лучший способ поменять байты 16-битных слов, а затем это.:
public static void Swap(byte[] data)
{
for (int i = 0; i < data.Length; i += 2)
{
byte b = data[i];
data[i] = data[i + 1];
data[i + 1] = b;
}
}
Есть ли у кого-нибудь идеи?
Ответ 1
В моей попытке подать заявку на награду Uberhacker я представляю следующее. Для моего тестирования я использовал исходный массив из 8 192 байтов и назвал SwapX2
100 000 раз:
public static unsafe void SwapX2(Byte[] source)
{
fixed (Byte* pSource = &source[0])
{
Byte* bp = pSource;
Byte* bp_stop = bp + source.Length;
while (bp < bp_stop)
{
*(UInt16*)bp = (UInt16)(*bp << 8 | *(bp + 1));
bp += 2;
}
}
}
Мой бенчмаркинг показывает, что эта версия более чем в 1,8 раза быстрее, чем код, представленный в исходном вопросе.
Ответ 2
Этот способ выглядит немного быстрее, чем метод в исходном вопросе:
private static byte[] _temp = new byte[0];
public static void Swap(byte[] data)
{
if (data.Length > _temp.Length)
{
_temp = new byte[data.Length];
}
Buffer.BlockCopy(data, 1, _temp, 0, data.Length - 1);
for (int i = 0; i < data.Length; i += 2)
{
_temp[i + 1] = data[i];
}
Buffer.BlockCopy(_temp, 0, data, 0, data.Length);
}
Мой бенчмаркинг предполагал, что метод вызывается повторно, так что изменение размера массива _temp
не является фактором. Этот метод основан на том факте, что половина байтового обмена может быть выполнена с помощью начального вызова Buffer.BlockCopy(...)
(с смещением позиции источника на 1).
Процитируйте это сами, если я полностью потеряю рассудок. В моих тестах этот метод занимает примерно 70% до тех пор, пока оригинальный метод (который я модифицировал, чтобы объявить byte b
вне цикла).
Ответ 3
Мне всегда это нравилось:
public static Int64 SwapByteOrder(Int64 value)
{
var uvalue = (UInt64)value;
UInt64 swapped =
( (0x00000000000000FF) & (uvalue >> 56)
| (0x000000000000FF00) & (uvalue >> 40)
| (0x0000000000FF0000) & (uvalue >> 24)
| (0x00000000FF000000) & (uvalue >> 8)
| (0x000000FF00000000) & (uvalue << 8)
| (0x0000FF0000000000) & (uvalue << 24)
| (0x00FF000000000000) & (uvalue << 40)
| (0xFF00000000000000) & (uvalue << 56));
return (Int64)swapped;
}
Я считаю, что вы найдете, что это самый быстрый метод, а также быть достаточно читабельным и безопасным. Очевидно, что это относится к 64-битным значениям, но тот же метод можно использовать для 32- или 16-.
Ответ 4
Ну, вы можете использовать XOR swapping трюк, чтобы избежать промежуточного байта. Однако это будет не так быстро, и я не удивлюсь, если IL будет точно таким же.
for (int i = 0; i < data.Length; i += 2)
{
data[i] ^= data[i + 1];
data[i + 1] ^= data[i];
data[i] ^= data[i + 1];
}