簡體   English   中英

C#4個byte []數組到int []的索引

[英]C# 4 indexes of byte[] arrays to int[]

我有一個字節數組

 byte[0]=00;
 byte[1]=01; 
 byte[2]=02;
 byte[3]=03;
    ...

並且我想按順序ex)00010203獲得四個字節並將它們轉換為int32數組,因此int [0]為66051

int[] result = new int[byteArray.Length / 4]; 
Buffer.BlockCopy(byteArray, 0, result, 0, byteArray.Length);

我嘗試使用上面的代碼,但結果卻大不相同。

我想你想要BitConverter.ToInt32()

var byteArray = new byte[] { 0x00, 0x01, 0x02, 0x03 };
int[] result = new int[byteArray.Length / 4];
for (int i = 0; i < result.Length; ++i)
{
    var srcBytes = byteArray.Skip(i * 4).Take(4);
    if (BitConverter.IsLittleEndian)
    {
        srcBytes = srcBytes.Reverse();
    }
    result[i] = BitConverter.ToInt32(srcBytes.ToArray(), 0);
}

盡管johns的回答是正確的,但其速度非常慢

這使用BufferCopy和按位交換,並且許多因素更快

基准測試

請注意,我不得不刪除johns,因為這花了很長時間進行測試

----------------------------------------------------------------------------
Mode             : Release (64Bit)
Test Framework   : .NET Framework 4.7.1 (CLR 4.0.30319.42000)
----------------------------------------------------------------------------
Operating System : Microsoft Windows 10 Pro
Version          : 10.0.17134
----------------------------------------------------------------------------
CPU Name         : Intel(R) Core(TM) i7-3770K CPU @ 3.50GHz
Description      : Intel64 Family 6 Model 58 Stepping 9
Cores (Threads)  : 4 (8)      : Architecture  : x64
Clock Speed      : 3901 MHz   : Bus Speed     : 100 MHz
L2Cache          : 1 MB       : L3Cache       : 8 MB
----------------------------------------------------------------------------

Total Benchmarks : Inputs (1) * Scales (5) * Benchmarks (3) * Runs (100) = 1,500

測試1

--- Standard input ------------------------------------------------------
| Value |  Average |  Fastest |    Cycles |    Garbage | Test |    Gain |
--- Scale 100 -------------------------------------------- Time 0.164 ---
| Mine2 | 0.012 ms | 0.004 ms |  43.913 K |   8.000 KB | N/A  | 55.16 % |
| MineR | 0.014 ms | 0.004 ms |  52.617 K |   8.000 KB | N/A  | 46.35 % |
| Mine  | 0.026 ms | 0.006 ms |  94.853 K |   7.461 KB | Base |  0.00 % |
--- Scale 1,000 ------------------------------------------ Time 0.114 ---
| Mine2 | 0.005 ms | 0.004 ms |  19.006 K |   8.000 KB | N/A  | 48.82 % |
| MineR | 0.005 ms | 0.004 ms |  19.763 K |   8.000 KB | N/A  | 46.95 % |
| Mine  | 0.009 ms | 0.008 ms |  34.456 K |   8.000 KB | Base |  0.00 % |
--- Scale 10,000 ----------------------------------------- Time 0.126 ---
| Mine2 | 0.009 ms | 0.008 ms |  33.715 K |  17.813 KB | N/A  | 72.23 % |
| MineR | 0.016 ms | 0.014 ms |  59.171 K |  17.813 KB | N/A  | 49.12 % |
| Mine  | 0.032 ms | 0.030 ms | 113.567 K |  59.719 KB | Base |  0.00 % |
--- Scale 100,000 ---------------------------------------- Time 0.180 ---
| Mine2 | 0.053 ms | 0.051 ms | 188.890 K | 105.680 KB | N/A  | 83.65 % |
| MineR | 0.109 ms | 0.103 ms | 384.946 K | 105.680 KB | N/A  | 66.26 % |
| Mine  | 0.323 ms | 0.277 ms |   1.135 M | 459.633 KB | Base |  0.00 % |
--- Scale 1,000,000 -------------------------------------- Time 0.709 ---
| Mine2 | 0.509 ms | 0.485 ms |   1.784 M | 984.586 KB | N/A  | 86.00 % |
| MineR | 1.155 ms | 1.049 ms |   4.048 M | 984.586 KB | N/A  | 68.22 % |
| Mine  | 3.636 ms | 3.269 ms |  12.711 M |   3.916 MB | Base |  0.00 % |
-------------------------------------------------------------------------

public static uint SwapBytes(uint x)
{
   // swap adjacent 16-bit blocks
   x = (x >> 16) | (x << 16);

   // swap adjacent 8-bit blocks
   return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
}

[Test("Mine", "", true)]
public int[] Test1(byte[] input, int scale)
{


   var result = new int[input.Length / 4];
   Buffer.BlockCopy(input, 0, result, 0, input.Length);

   return result.Select(x => (int)SwapBytes((uint)x))
                .ToArray();

}

我的2

[Test("Mine2", "", false)]
public unsafe int[] Test2(byte[] input, int scale)
{
   var result = new int[input.Length / 4];
   Buffer.BlockCopy(input, 0, result, 0, input.Length);

   fixed (int* pResult = result)
   {
      var len = pResult + result.Length;

      for (var p = pResult; p < len; p++)
      {
         var x = (*p >> 16) | (*p << 16);
         *p = (int)(((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8));
      }
   }

   return result;
}

約翰

[Test("john", "", false)]
public unsafe int[] Test4(byte[] input, int scale)
{
   var result = new int[input.Length / 4];
   for (int i = 0; i < result.Length; ++i)
   {
      var srcBytes = input.Skip(i * 4).Take(4);
      if (System.BitConverter.IsLittleEndian)
      {
         srcBytes = srcBytes.Reverse();
      }
      result[i] = System.BitConverter.ToInt32(srcBytes.ToArray(), 0);
   }

   return result;
}

礦工

[Test("MineR", "", false)]
public int[] Test3(byte[] input, int scale)
{
   int numBytes = input.Length;
   int numInts = numBytes / 4;

   if (numBytes / 4d != numInts)
      throw new Exception();

   if (numInts == 0)
      return new int[0];

   var ints = new int[numInts];

   unsafe
   {
      fixed (byte* pBytes = input)
         fixed (int* pInts = ints)
         {
            byte* rawInt = (byte*)pInts;

            for (int i = 0; i < numBytes; i += 4)
            {
               for (int j = 0; j < 4; j++)
               {
                  rawInt[i + j] = pBytes[3 - j + i];
               }
            }

         }
   }

   return ints;
}

原始郵件

public static class MyExtension
{
   public static uint SwapBytes(uint x)
   {
      // swap adjacent 16-bit blocks
      x = (x >> 16) | (x << 16);
      // swap adjacent 8-bit blocks
      return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
   }

   public static int[] GetInts(this byte[] source)
   {
      var result = new int[source.Length / 4];
      Buffer.BlockCopy(source, 0, result, 0, source.Length);
      return result.Select(x => (int)SwapBytes((uint)x)).ToArray();
   }
}

用法

var byteArray = new byte[4*100000];
var ints = byteArray.GetInts();

更新資料

使用固定和不安全的方法,這又快了大約10倍

public unsafe static int[] GetInts3(this byte[] source)
{
   var result = new int[source.Length / 4];
   Buffer.BlockCopy(source, 0, result, 0, source.Length);

   fixed (int* pResult = result)
   {
      var len = pResult + result.Length;

      for (var p = pResult; p < len; p++)
      {
         var x = (*p >> 16) | (*p << 16);
         *p = (int)(((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8));
      }
   }

   return result;
}

作為不安全的替代方法,您可以嘗試以下操作:

public static int[] GetIntsUnsafe(byte[] bytes)
{
    int numBytes = bytes.Length;
    int numInts = numBytes / 4;
    if (numBytes / 4d != numInts) throw new Exception();
    if (numInts == 0) return new int[0];

    var ints = new int[numInts];

    unsafe
    {
        fixed (byte* pBytes = bytes)
        fixed (int* pInts = ints)
        {
            byte* rawInt = (byte*)pInts;

            for (int i = 0; i < numBytes; i += 4)
            {
                for (int j = 0; j < 4; j++)
                {
                    rawInt[i + j] = pBytes[3 - j + i];
                }
            }

        }
    }

    return ints;
}

我在Release,AnyCPU中對三個答案進行了性能測試(在撰寫本文時),沒有附帶調試器以獲取:

Unsafe Small: 22
Unsafe Large: 5
John Small: 816
John Large: 23628
General Small: 49 // 266 with Linq ToArray
General Large 4 // 29 with Linq ToArray

測試代碼:

Random r = new Random(0);
var byteSmall = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x03, 0x05, 0x07, 0x23 };
var byteLarge = new byte[10000];
for (int i = 0; i < byteLarge.Length; i++) byteLarge[i] = (byte)r.Next(255);

int countSmall = 2_000_000;
int countLarge = 1_000;

Stopwatch swUnsafeSmall = Stopwatch.StartNew();
for (int i = 0; i < countSmall; i++) GetIntsUnsafe(byteSmall);
swUnsafeSmall.Stop();

Console.WriteLine("Unsafe Small: " + swUnsafeSmall.ElapsedMilliseconds);

Stopwatch swUnsafeLarge = Stopwatch.StartNew();
for (int i = 0; i < countLarge; i++) GetIntsUnsafe(byteLarge);
swUnsafeLarge.Stop();

Console.WriteLine("Unsafe Large: " + swUnsafeLarge.ElapsedMilliseconds);

Stopwatch swJohnSmall = Stopwatch.StartNew();
for(int i = 0; i < countSmall;i++)
    GetIntsJohn(byteSmall);
swJohnSmall.Stop();

Console.WriteLine("John Small: " + swJohnSmall.ElapsedMilliseconds);

Stopwatch swJohnLarge = Stopwatch.StartNew();
for(int i = 0; i < countLarge;i++)
    GetIntsJohn(byteLarge);
swJohnLarge.Stop();

Console.WriteLine("John Large: " + swJohnLarge.ElapsedMilliseconds);


Stopwatch swGeneralSmall = Stopwatch.StartNew();
for(int i = 0; i < countSmall;i++)
    GetIntsGeneral(byteSmall);
swGeneralSmall.Stop();

Console.WriteLine("General Small: " + swGeneralSmall.ElapsedMilliseconds);

Stopwatch swGeneralLarge = Stopwatch.StartNew();
for(int i = 0; i < countLarge;i++)
    GetIntsGeneral(byteLarge);
swGeneralLarge.Stop();

Console.WriteLine("General Large: " + swGeneralLarge.ElapsedMilliseconds);


Console.ReadLine();

還有我的John和General的代碼版本。 (我編輯了TheGeneral的代碼以不復制數組):

public static int[] GetIntsJohn(byte[] byteArray)
{
    int[] result = new int[byteArray.Length / 4];
    for (int i = 0; i < result.Length; ++i)
    {
        var srcBytes = byteArray.Skip(i * 4).Take(4);
        if (BitConverter.IsLittleEndian)
        {
            srcBytes = srcBytes.Reverse();
        }
        result[i] = BitConverter.ToInt32(srcBytes.ToArray(), 0);
    }

    return result;
}



public static uint SwapBytes(uint x)
{
    // swap adjacent 16-bit blocks
    x = (x >> 16) | (x << 16);
    // swap adjacent 8-bit blocks
    return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
}

public static int[] GetIntsGeneral(byte[] source)
{
    var result = new int[source.Length / 4];
    Buffer.BlockCopy(source, 0, result, 0, source.Length);
    for(int i= 0;i<result.Length;i++)
    {
        result[i] = (int) SwapBytes((uint) result[i]);
    }

    return result;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM