任意 Word32
number 可以表示为 Word8
的线性组合编号如下:
x = a + b * 2^8 + c * 2^16 + d * 2^24
换句话说,这是
x
的表示在基地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
的所有重复感到恼火。 ,但转换是必要的,以便类型可以匹配。提前致谢。
最佳答案
通过为结果定义不同的类型,使用 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
关于无符号整数函数的性能改进,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14471737/