2009-10-23 42 views
10

比较快的方式有一定是一个更快,更好的方式来交换的16位字字节那么这:交换字节序在C#与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; 
    } 
} 

有没有人有一个想法?

+2

你的解决方案似乎是一个很好的解决方案,只是如果你的数据是奇数长度的,你的代码将抛出数组超出限制的异常。 – NawaMan 2009-10-23 00:53:15

+1

如果他交换16位字,那么他的数据永远不会有奇数长度。 – 2009-10-23 00:59:32

+0

是的,这将是一个私人的方法,它将保证有16位字。 – initialZero 2009-10-23 01:02:34

回答

7

在试图申请Uberhacker奖时,我提交了以下内容。对于我的测试中,我使用的8,192字节的源阵列,并呼吁SwapX2 10万次:

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

1

那么,你可以使用XOR swapping trick来避免中间字节。然而,它不会更快,如果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]; 
} 
+1

好的。但是这样看起来有点令人困惑。而维基百科声称“在现代(桌面)CPU上,XOR技术比使用临时变量进行交换要慢得多。”好吧。感谢性感的解决方案。 – initialZero 2009-10-23 01:23:10

+0

是的,我认为我们可以说的就是它很整洁。我只是对它进行了基准测试,得到的结果与您的解决方案相同。所以,其中一种形式可能会优化到另一种形式。 – 2009-10-23 01:25:04

6

这种方式似乎是在原来的问题略高于方法快:

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以外的循环)。

+0

Uberhacker奖!我希望有一个大的温度调整比一个就地交换更昂贵。这只是一个内存泄漏,只是临时坐着。 – initialZero 2009-10-23 02:07:59

+1

@initialZero:在我的基准测试中,我最初将其尺寸与我的测试阵列大小相同,因此在那里没有任何成本。像这样的温度变量一般以牺牲内存为代价来购买速度,这可能或可能不是一个好的决定。 – MusiGenesis 2009-10-23 02:12:09

+0

@MusiGenesis你可以随时在交换结束时设置temp = null来修复泄漏。这绝对是一个很酷的解决方案。谢谢。 – initialZero 2009-10-23 02:17:17

4

我一直很喜欢这样的:

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