我们有了一个更快和更好的方式来交换字节的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;
    }
}

有没有人有主意吗?

有帮助吗?

解决方案

在我申请Uberhacker奖时,我提交以下内容。对于我的测试,我使用了一个8,192字节的Source数组,并且称为 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倍。

其他提示

这种方式似乎比原始问题中的方法稍快:

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)。

如果我完全失去理智,请自行预测。在我的测试中,只要原始方法(我修改为在循环外部声明 byte b ),此方法大约需要70%。

我一直很喜欢这个:

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 - 。

下一个方法,在我的测试,几乎3倍的速度作为接受的答案。(总是快上超过3个字或六个字节,稍慢一些,在小于或等于三个字或六个字节。) (注意,所接受的答案可以读写的边界之外的阵列。)

(更新,同时有一个指针就没有必要调用的财产获得的长度。使用这一指针是一位速度较快,但是要求运行时检查,或者,如在下一个例子,一个项目构建设为每个平台。定义X86和64下的每个构成。)

static unsafe void SwapV2(byte[] source)
{
    fixed (byte* psource = source)
    {
#if X86
        var length = *((uint*)(psource - 4)) & 0xFFFFFFFEU;
#elif X64
        var length = *((uint*)(psource - 8)) & 0xFFFFFFFEU;
#else
        var length = (source.Length & 0xFFFFFFFE);
#endif
        while (length > 7)
        {
            length -= 8;
            ulong* pulong = (ulong*)(psource + length);
            *pulong = ( ((*pulong >> 8) & 0x00FF00FF00FF00FFUL)
                      | ((*pulong << 8) & 0xFF00FF00FF00FF00UL));
        }
        if(length > 3)
        {
            length -= 4;
            uint* puint = (uint*)(psource + length);
            *puint = ( ((*puint >> 8) & 0x00FF00FFU)
                     | ((*puint << 8) & 0xFF00FF00U));
        }
        if(length > 1)
        {
            ushort* pushort = (ushort*)psource;
            *pushort = (ushort) ( (*pushort >> 8)
                                | (*pushort << 8));
        }
    }
}

五个测试与300.000次8192字节

  • SwapV2:1055,1051,1043,1041,1044
  • SwapX2:2802,2803,2803,2805,2805

五个测试与50.000.000次6个字节

  • SwapV2:1092,1085,1086,1087,1086
  • SwapX2:1018,1019,1015,1017,1018

但是如果数据是大型和性能真正重要的事情,你可以使用证或参考.(13倍。) https://pastebin.com/WaFk275U

测试的5倍,100000循环8192字节或4096字

  • SwapX2:226,223,225,226,227分:223
  • SwapV2:113,111,112,114,112分:111
  • SwapA2:17、17日、17日、17日、16分:16

好吧,您可以使用 XOR交换技巧来避免中间字节。但是,它不会更快,如果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];
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top