2013-01-23 32 views
3

任何Word32數目可如下表達爲Word8號的線性組合:性能改進作用

x = a + b * 2^8 + c * 2^16 + d * 2^24 

換句話說,這是在鹼的2^8x表示。爲了獲得這些因素,我實現了以下功能:

word32to8 :: Word32 -> (Word8,Word8,Word8,Word8) 
word32to8 n = (fromIntegral a,fromIntegral b,fromIntegral c,fromIntegral d) 
    where 
    (d,r1) = divMod n (2^24) 
    (c,r2) = divMod r1 (2^16) 
    (b,a) = divMod r2 (2^8) 

它工作正常,但由於我的程序正在使用此功能一堆的時候,我還以爲你們可以給我如何改善的想法(如果可能)執行此操作。任何小小的改進對我來說都是好的,無論是在時間還是空間上。對我來說,它看起來非常簡單,以至於無法實現性能提升,但我仍然想問這個問題,以防萬一我缺少某些東西。

順便說一下,我對fromIntegral的所有重複感到惱火,但轉換是必要的,因此類型可以匹配。

在此先感謝。

+0

我認爲一個更快但可能不太便攜的pproach將使用'Word32'的'Storable'實例來訪問底層的字節級表示,然後直接從中讀取所有四個字節。 –

+1

@GabrielGonzalez:這可能比4'divMod's更快,但它絕對不是最佳選擇。使用'可存儲'意味着分配一個新的內存塊,複製到它並回讀。 @ ertes的解決方案將避免額外的分配和複製。 –

回答

13

您可以通過定義不同類型的結果,利用一個GHC擴展和使用按位運算,而不是得到一個重大的性能提升:

data Split = 
    Split {-# UNPACK #-} !Word8 
      {-# UNPACK #-} !Word8 
      {-# UNPACK #-} !Word8 
      {-# UNPACK #-} !Word8 

splitWord :: Word32 -> Split 
splitWord x = 
    Split (fromIntegral x) 
      (fromIntegral (shiftR x 8)) 
      (fromIntegral (shiftR x 16)) 
      (fromIntegral (shiftR x 24)) 

這段代碼的四倍多比你原來快通過使用以下改進功能:

  • 而不是使用非嚴格元組類型我已經定義了嚴格類型Split
  • 我已經解壓該類型的字段以擺脫大多數內存分配和垃圾回收。
  • 我已經從divMod轉換爲shiftR。你實際上不需要模操作,所以我放棄了它。

另一種提高速度的方法是根本不經歷具體的數據類型。您可能想要使用字節進行計算,因此我們跳過存儲和檢索它們的步驟。相反,我們通過splitWord功能的延續

splitWord :: (Word8 -> Word8 -> Word8 -> Word8 -> r) -> Word32 -> r 
splitWord k x = 
    k (fromIntegral x) 
     (fromIntegral (shiftR x 8)) 
     (fromIntegral (shiftR x 16)) 
     (fromIntegral (shiftR x 24)) 

如果你仍然想保存的字節數,你可以通過Split構造的延續:

splitWord Split 123456 

但現在你也可以只是執行你想要執行的計算:

splitWord (\a b c d -> a + b + c + d) 123456 
+2

可能值得指出的是,即使你不想一路去位移,使用「quot」比「divMod」快得多。 –

+0

根據我的基準,這是不正確的。但我知道它曾經是真的。我在GHC 7.6.1的i5上編譯並使用-O2編譯。 – ertes

+0

這是一個很棒的答案!謝謝。一切都很完美。我不知道這些_bit-wise_操作。它看起來正是我所需要的。也作爲性能改進。然後,我嘗試了帶有嚴格未裝箱字段的「數據」。它更快地完成了代碼。最後,我申請了_continuation_想法並且工作得非常棒。 –