2009-10-23 43 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位。