无符号整数函数的性能改进

标签 performance haskell

任意 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/

    相关文章:

    c++ - C中If-Else和三元运算符之间的速度差异...?

    java - 缓冲区大小如何影响 NIO channel 性能?

    haskell - 为什么 Haskell 中更高级别的类型如此脆弱

    c# - 在语法上是否需要不同的打开和关闭定界符?

    c++ - 相当于 C++ 类型对的 Haskell

    c++ - 有很多读者时使用 pthread_rwlock 的效率

    java - 为什么 HashMap 比 HashSet 快?

    Javascript包含动态SRC技术="url"

    haskell - 如何绑定(bind)函数中的第二个参数而不是第一个参数(以优雅的方式)?

    haskell - 从 Haskell 中的 where 子句函数访问参数