3

任意の数は、次のように数Word32の線形結合として表すことができます。Word8

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

つまり、これはxbase での の表現です2^8。これらの要因を取得するために、次の関数を実装しました。

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ですが、型を合わせるためには変換が必要です。

前もって感謝します。

4

1 に答える 1

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

このコードは、次の改善を使用することで、元の関数よりも 4 倍以上高速です。

  • 非厳密なタプル型を使用する代わりに、厳密な型を定義しましたSplit
  • ほとんどのメモリ割り当てとガベージ コレクションを取り除くために、その型のフィールドをアンパックしました。
  • から に切り替えましdivModshiftR。実際には剰余演算を行う必要はないので、削除しました。

速度を向上させるもう 1 つの方法は、具体的なデータ型をまったく使用しないことです。おそらくバイトで計算を実行したいので、それらを保存して取得するステップをスキップします。代わりに、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
于 2013-01-23T03:35:07.277 に答える