为什么换档比给旧哈斯克尔供电慢呢? 如何让它更快?
当第一次搜索到我的代码很慢的时候,我真的很惊讶,不期望这样,驱动(或乘法)可以更快,所以移位代码中的某些东西真的很慢。
(整数)供电的代码
{-# 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> cmd / v:on / c“echo!TIME!&pow.exe 33 40000000&echo!TIME!”
1:24:29,02
1
1:24:41,48
- 12.46秒 供电
c: ghc ghc-6.10.4 bin> cmd / v:on / c“echo!TIME!&shift.exe 3 200000000&echo!TIME!”
1:27:08,76
0
1:27:22,06
- 13.30秒 换班
c: ghc ghc-7.6.3 bin> cmd / v:on / c“echo!TIME!&pow.exe 33 40000000&echo!TIME!”
2:19:29,39
1
2:19:37,06
- 7.67秒 供电(所以供电有所改善)
c: ghc ghc-7.6.3 bin> cmd / v:on / c“echo!TIME!&shift.exe 3 200000000&echo!TIME!”
2:20:49,61
0
2:20:49,69
- 0.08秒 (这意味着加速大约150倍)
甚至(这里有20亿比特的转换):
c: ghc ghc-7.6.3 bin> cmd / v:on / c“echo!TIME!&shift.exe 3 2000000000&echo!TIME!”
3:07:22,05
0
3:07:22,56
- 0.51秒
在运行中,这些数字相当大,以至于看到很长的运行时间。 在第一个代码中,我们计算33 ^ 40000000(mod 2),在第二个代码3 * 2 ^ 200000000(mod 2)中。 mod操作(或别的东西)必须看到不是0的时间(因为在这种情况下,haskell不会计算它)。 如前所述,电力供应速度更快,并注意到在这种情况下,33 ^ 40000000大于3 * 2 ^ 200000000。 此外在内存使用上,你可以看到3 ^ 200000000也是在最新的haskell上计算的,所以在这里没有深层次的优化技巧。
这个旧的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 wired-in软件包发生冲突ghc-prim映射到ghc-prim-0.1.0.0 wired-in软件包整数映射到整数-0.1.0.1线内包基底映射到基-4.1.0.0连线包中rts映射到rts-1.0连线包中haskell98映射到haskell98-1.0.1.0连线包syb映射到syb -0.1.0.1线内包模板-haskell映射到模板-haskell-2.3.0.1线内包dph-seq映射到dph-seq-0.3线内包dph-par映射到dph-par-0.3 Hsc静态标志:-static
我的猜测是GHC的旧版本没有针对Integer
转换的专门实现,因此会回落到默认的Haskell实现,请参阅Data.Bits
:
shift x i | i >= 0 = x * 2^i
| otherwise = x `div` 2^(-i)
但是,当前版本的左右偏移都是基于GMP的primops,请参阅integer-gmp
包中的GHC.Integer.Type
模块中的shiftLInteger
和shiftRInteger
函数。
上一篇: Why shifting is slower than powering on old haskell !? How to make it faster?