Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 为什么用“GHC-O2”对本机列表求和比对教会编码的列表求和慢?_Algorithm_Performance_List_Haskell - Fatal编程技术网

Algorithm 为什么用“GHC-O2”对本机列表求和比对教会编码的列表求和慢?

Algorithm 为什么用“GHC-O2”对本机列表求和比对教会编码的列表求和慢?,algorithm,performance,list,haskell,Algorithm,Performance,List,Haskell,为了测试church编码列表与用户定义列表和本地列表的性能,我准备了3个基准测试: 用户定义的列表 本地列表 教会名单 基准测试结果出乎意料: 用户定义的列表 本地列表 教会名单 有人会认为,有了针对本机列表的大量特定优化,它们的性能会最好。然而,church列表的性能比它们高出100倍,比用户定义的ADT高出2250倍。我用GHC-O2编译了所有程序。我尝试用foldl'替换sum,结果相同。我尝试添加用户输入,以确保church list版本未优化为常量arkeet在#haskell上指出,

为了测试church编码列表与用户定义列表和本地列表的性能,我准备了3个基准测试:

用户定义的列表 本地列表 教会名单 基准测试结果出乎意料:

用户定义的列表 本地列表 教会名单 有人会认为,有了针对本机列表的大量特定优化,它们的性能会最好。然而,church列表的性能比它们高出100倍,比用户定义的ADT高出2250倍。我用
GHC-O2
编译了所有程序。我尝试用
foldl'
替换
sum
,结果相同。我尝试添加用户输入,以确保church list版本未优化为常量
arkeet
在#haskell上指出,通过检查Core,本机版本有一个中间列表,但为什么?强制分配额外的
反向
,所有3个执行大致相同

GHC 7.10具有分析功能,它允许我们根据
foldr
定义
foldl
,从而让左侧折叠(包括
sum
)参与融合。GHC 7.8还使用
foldl
定义了
sum
,但它不能将列表融合在一起。因此,GHC 7.10的性能最佳,与教会版本相同

Church版本是在任何GHC版本中进行优化的儿童游戏。我们只需要将
(+)
0
内联到
fenumTil
,然后我们就有了一个明显的尾部递归
go
,它可以很容易地取消绑定,然后由代码生成器转换成一个循环


用户定义的版本不是尾部递归的,它在线性空间中工作,这当然会破坏性能

你所说的“三者表现大致相同”是什么意思?不相关,但…:
go 0结果
应该是
result(+)nil
(对吗?)?(也就是说,如果它不是绝对巨大的话。)值得一提的是,在我的机器上,您的原生列表版本在GHC 7.6.3和GHC 7.8.4上使用0.76秒,但在GHC 7.10.1上仅使用0.05秒。Church版本在这三个方面都需要大约0.06秒(哦,自定义列表版本在这三个方面都慢得很。但是考虑到它的编写方式与其他两个不同,这是可以理解的)省略了GHC Core,因为除了我上面写的内容之外,它没有向我们展示任何有趣的东西。我想看看它:(但是好吧!谢谢András,我知道有人会知道答案。呃,你确定它被编译成循环吗?可执行文件甚至可以处理非常非常非常大的数字。看起来它被编译成了求和公式…(?)(也许LLVM本身正在将循环编译成公式?@Viclib计算机非常擅长添加大数字。它们不擅长存储大数字。
data List a = Cons a (List a) | Nil deriving Show
lenumTil n        = go n Nil where
    go 0 result   = result
    go n result   = go (n-1) (Cons (n-1) result)
lsum Nil          = 0
lsum (Cons h t)   = h + (lsum t)

main = print (lsum (lenumTil (100000000 :: Int)))
main = print $ sum ([0..100000000-1] :: [Int])
fsum   = (\ a -> (a (+) 0))
fenumTil n cons nil = go n nil where
    go 0 result    = result
    go n result    = go (n-1) (cons (n-1) result)
main = print $ (fsum (fenumTil (100000000 :: Int)) :: Int)
-- 4999999950000000
-- real 0m22.520s
-- user 0m59.815s
-- sys  0m20.327s
-- 4999999950000000
-- real 0m0.999s
-- user 0m1.357s
-- sys  0m0.252s
-- 4999999950000000
-- real 0m0.010s
-- user 0m0.002s
-- sys  0m0.003s