Самый быстрый способ конвертировать int в 4 байта в С#
Что такое быстрый способ преобразования int в 4 байта в С#?
Самый быстрый, как во время выполнения, а не время разработки.
Мое собственное решение - это код:
byte[] bytes = new byte[4];
unchecked
{
bytes[0] = (byte)(data >> 24);
bytes[1] = (byte)(data >> 16);
bytes[2] = (byte)(data >> 8);
bytes[3] = (byte)(data);
}
Сейчас я вижу, что мое решение превосходит как struct
, так и BitConverter
пару тиков.
Я думаю, что небезопасный, вероятно, самый быстрый вариант, и принять это как ответ, но я бы предпочел использовать управляемый вариант.
Ответы
Ответ 1
Байт * листинг с использованием небезопасного кода является самым быстрым:
unsafe static void Main(string[] args) {
int i = 0x12345678;
byte* pi = (byte*)&i;
byte lsb = pi[0];
// etc..
}
Что и делает BitConverter, этот код позволяет избежать затрат на создание массива.
Ответ 2
Что такое быстрый способ преобразования int в 4 байта в С#?
Использование BitConverter и GetBytes перегрузка который принимает 32-битное целое число:
int i = 123;
byte[] buffer = BitConverter.GetBytes(i);
Ответ 3
Самый быстрый способ - это структура, содержащая 4 байта.
- В определенном макете (в позиции байта 0, 1, 2, 3
- И int32, начинающийся с позиции 0.
- Поместите в 4 переменные, зачитайте байт.
- завершенности.
Значительно быстрее, чем битконвертер.
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx
имеет необходимый атрибут.
[StructLayout(LayoutKind.Explicit)]
struct FooUnion
{
[FieldOffset(0)]
public byte byte0;
[FieldOffset(1)]
public byte byte1;
[FieldOffset(2)]
public byte byte2;
[FieldOffset(3)]
public byte byte3;
[FieldOffset(0)]
public int integer;
}
Ответ 4
Я провел исследование времени, необходимого для сериализации базового типа в байтовый массив. Я сделал это для случая, когда у вас уже есть массив и смещение, где вы хотите поместить свои данные. Я думаю, что действительно важный случай по сравнению с теоретическими получает массив из 4 байтов, потому что когда вы сериализуете что-то, то это именно то, что вам нужно. Я понял, что ответ на какой метод быстрее зависит от того, какой тип вы хотите сериализовать. Я пробовал несколько методов:
- Небезопасная ссылка с дополнительной проверкой переполнения буфера
- GetBytes + последующий Buffer.BulkCopy(это по существу то же самое, что и 1 плюс служебные)
- Прямое назначение со сдвигом (
m_Bytes[offset] = (byte)(value >> 8)
- Прямое назначение со сдвигом и побитовым и
m_Bytes[offset] = (byte)((i >> 8) & 0xFF)
Я провел весь тест 10 миллионов раз. Ниже приведены результаты в миллисекундах
Long Int Short Byte Float Double
1 29 32 31 30 29 34
2 209 233 220 212 208 228
3 63 24 13 8 24 44
4 72 29 14
Как вы видите, небезопасный способ намного быстрее для длинных и двойных (неподписанные версии примерно такие же, как и их подписанные версии, поэтому они не находятся в таблице). Для short/int/float самым быстрым способом является назначение 2/4/4 со сдвигом. Для байта наиболее быстрым является, очевидно, простое назначение. Так что в отношении исходного вопроса - путь назначения является лучшим. Это пример такой функции самым быстрым способом:
public static void WriteInt(byte[] buffer, int offset, int value)
{
m_BytesInt[offset] = (byte)(value >> 24);
m_BytesInt[offset + 1] = (byte)(value >> 16);
m_BytesInt[offset + 2] = (byte)(value >> 8);
m_BytesInt[offset + 3] = (byte) value;
}
P.S. Тесты выполнялись в среде x64 с кодом, скомпилированным для процессора (который был x64 при запуске) в режиме выпуска.
Ответ 5
Обратите внимание, что битконвертер может быть не самым быстрым, как показано ниже.
Используйте класс BitConverter
, в частности GetBytes
, который принимает параметр Int32
:
var myInt = 123;
var bytes = BitConverter.GetBytes(myInt);
Вы можете использовать BitConverter.IsLittlEndian
, чтобы определить порядок байтов на основе архитектуры процессора.
EDIT: нижеприведенный тест не является окончательным из-за оптимизации компилятора.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
[StructLayout(LayoutKind.Explicit)]
struct FooUnion
{
[FieldOffset(0)]
public byte byte0;
[FieldOffset(1)]
public byte byte1;
[FieldOffset(2)]
public byte byte2;
[FieldOffset(3)]
public byte byte3;
[FieldOffset(0)]
public int integer;
}
class Program
{
static void Main(string[] args)
{
testUnion();
testBitConverter();
Stopwatch Timer = new Stopwatch();
Timer.Start();
testUnion();
Timer.Stop();
Console.WriteLine(Timer.ElapsedTicks);
Timer = new Stopwatch();
Timer.Start();
testBitConverter();
Timer.Stop();
Console.WriteLine(Timer.ElapsedTicks);
Console.ReadKey();
}
static void testBitConverter()
{
byte[] UnionBytes;
for (int i = 0; i < 10000; i++)
{
UnionBytes = BitConverter.GetBytes(i);
}
}
static void testUnion()
{
byte[] UnionBytes;
for (int i = 0; i < 10000; i++)
{
FooUnion union = new FooUnion() { integer = i };
UnionBytes = new byte[] { union.byte0, union.byte1, union.byte2, union.byte3 };
}
}
}
}
Ответ 6
Похоже, что многие из нас рассуждают о том, что BitConverter
больше, чем выделенный struct
. На основе исходного кода BCL BitConverter.GetBytes()
выглядит следующим образом:
public static unsafe byte[] GetBytes(int value)
{
byte[] buffer = new byte[4];
fixed (byte* bufferRef = buffer)
{
*((int*)bufferRef) = value;
}
return buffer;
}
Что из моей точки зрения является более чистым и кажется более быстрым, чем создание 1 целых + 4 байтовых назначения для явной структуры, такой как этот.
[StructLayout(LayoutKind.Explicit)]
struct IntByte
{
[FieldOffset(0)]
public int IntVal;
[FieldOffset(0)]
public byte Byte0;
[FieldOffset(1)]
public byte Byte1;
[FieldOffset(2)]
public byte Byte2;
[FieldOffset(3)]
public byte Byte3;
}
new IntByte { IntVal = 10 } -> Byte0, Byte1, Byte2, Byte3.
Ответ 7
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
unsafe{
byte[] byteArray = new byte[4];
for(int i = 0; i != int.MaxValue; ++i)
{
fixed(byte* asByte = byteArray)
*((int*)asByte) = 43;
}
}
Console.WriteLine(sw.ElapsedMilliseconds);
Console.Read();
}
}
Средние значения составляют около 2770 мс на моей машине, а
[StructLayout(LayoutKind.Explicit)]
struct Switcher
{
[FieldOffset(0)]
public int intVal;
[FieldOffset(0)]
public byte b0;
[FieldOffset(1)]
public byte b1;
[FieldOffset(2)]
public byte b2;
[FieldOffset(3)]
public byte b3;
}
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
byte[] byteArray = new byte[4];
Switcher swi = new Switcher();
for(int i = 0; i != int.MaxValue; ++i)
{
swi.intVal = 43;
byteArray[0] = swi.b0;
byteArray[1] = swi.b1;
byteArray[2] = swi.b2;
byteArray[3] = swi.b3;
}
Console.WriteLine(sw.ElapsedMilliseconds);
Console.Read();
}
}
В среднем около 4510 мс.
Ответ 8
Я думаю, что это может быть самый быстрый способ в С#.. (с байтовым массивом, инициализированным до 4x int stream w/int32
private MemoryStream Convert(int[] Num, byte[] Bytes)
{
Buffer.BlockCopy(Num, 0, Bytes, 0, Bytes.Length);
MemoryStream stream = new MemoryStream(Bytes);
return stream;
}