为什么换班的速度比老式的哈斯克尔要慢!如何让它更快?

时间:2013-09-02 11:09:09

标签: performance haskell optimization bit-shift

当我第一次搜索我的代码很慢的地方时,我真的很惊讶,没有预料到这一点,那就是动力(或乘法) 可以更快,因此班次代码中的某些内容非常慢。

(整数)供电的代码

{-# OPTIONS_GHC -O2 #-}

import System.Environment(getArgs)

main = do
  [a,b] <- getArgs
  let c = ( read a::Integer ) ^ ( read b::Int )
  print ( mod c 2 )

转移的示例代码

{-# OPTIONS_GHC -O2 #-}

import Data.Bits
import System.Environment(getArgs)

main = do
  [a,b] <- getArgs
  let c = shift ( read a::Integer ) ( read b::Int )
  print( mod c 2 )

我在旧的和最新的haskell上运行:

c:\ ghc \ ghc-6.10.4 \ bin&gt; cmd / v:on / c“echo!TIME!&amp; pow.exe 33 40000000&amp; echo!TIME!”
 1:24:29,02
1
 1:24:41,48
- 12.46秒供电

c:\ ghc \ ghc-6.10.4 \ bin&gt; cmd / v:on / c“echo!TIME!&amp; shift.exe 3 200000000&amp; echo!TIME!”
 1:27:08,76
0
 1:27:22,06
- 13.30秒转移

c:\ ghc \ ghc-7.6.3 \ bin&gt; cmd / v:on / c“echo!TIME!&amp; pow.exe 33 40000000&amp; echo!TIME!”
 2:19:29,39
1
 2:19:37,06
- 7.67秒用于供电(因此供电有所改善)

c:\ ghc \ ghc-7.6.3 \ bin&gt; cmd / v:on / c“echo!TIME!&amp; shift.exe 3 200000000&amp; echo!TIME!”
 2:20:49,61
0
 2:20:49,69
- 0.08秒用于转移(这意味着加速大约为150)


或甚至(此处20亿位移位):
c:\ ghc \ ghc-7.6.3 \ bin&gt; cmd / v:on / c“echo!TIME!&amp; shift.exe 3 2000000000&amp; echo!TIME!”
 3:07:22,05
0
 3:07:22,56
- 0.51秒


在跑步中,数字非常大,看起来运行时间很长。 在第一个代码中,我们计算33 ^ 40000000(mod 2),在第二个代码中3 * 2 ^ 200000000(mod 2)。模组 操作(或其他东西)必须要看到不是0时间(因为在这种情况下haskell不会计算它)。如上所述 供电速度更快,并且还注意到在这种情况下33 ^ 40000000大于3 * 2 ^ 200000000。 此外,在内存使用方面,您可以看到最新的haskell也计算了3 ^ 200000000,因此没有深度优化技巧 这里。

是否有可能在这个旧的haskell版本中获得加速?我有兴趣在两个方向上移动(大整数), 我们可以假设我们以64位的倍数(或63或32或31;在haskell上的整数表示中的单词大小)移位, 所以没有环绕。

尝试计算2 ^ n然后执行乘法(或除法)来进行移位,但它没有给旧的haskell加速。

UPDATE
使用-v标志运行编译器开始打印:(我也可以发布其余的)格拉斯哥Haskell编译器,版本6.10.4,适用于Haskell 98,第2阶段由GHC版本6.10.1启动 使用包配置文件:C:\ ghc \ ghc-6.10.4 \ package.conf 隐藏包base-3.0.3.1以避免与更高版本base-4.1.0.0冲突 接线包ghc-prim映射到ghc-prim-0.1.0.0 有线包整数映射到整数-0.0.0.1 有线包基地映射到base-4.1.0.0 有线包rts映射到rts-1.0 有线包haskell98映射到haskell98-1.0.1.0 有线包syb映射到syb-0.1.0.1 有线包模板-haskell映射到template-haskell-2.3.0.1 有线包dph-seq映射到dph-seq-0.3 有线包dph-par映射到dph-par-0.3 Hsc静态标志:-static

1 个答案:

答案 0 :(得分:2)

我的猜测是GHC的旧版本没有Integer转换的专门实现,因此回到默认的Haskell实现,请参阅Data.Bits

shift x i | i >= 0    = x * 2^i
          | otherwise = x `div` 2^(-i)  

但是,当前版本的左右移位都有基于GMP的primops,请参阅shiftLInteger shiftRInteger模块中的integer-gmp和{{1}}函数封装