【发布时间】:2012-06-08 05:16:09
【问题描述】:
我已经在Haskell 和C++(ideone 链接)中为Project Euler's Challenge 14 编写了代码。他们都记得他们之前在数组中所做的任何计算。
分别使用ghc -O2 和g++ -O3,C++ 的运行速度比 Haskell 版本快 10-15 倍。
虽然我了解 Haskell 版本可能运行速度较慢,而且 Haskell 是一种更好的编写语言,但很高兴知道我可以对 Haskell 版本进行一些代码更改以使其运行得更快(最好在一个因素内) 2 或 3 个 C++ 版本)?
Haskell 代码在这里:
import Data.Array
import Data.Word
import Data.List
collatz_array =
let
upperbound = 1000000
a = array (1, upperbound) [(i :: Word64, f i :: Int) | i <- [1..upperbound]]
f i = i `seq`
let
check_f i = i `seq` if i <= upperbound then a ! i else f i
in
if (i == 1) then 0 else (check_f ((if (even i) then i else 3 * i + 1) `div` 2)) + 1
in a
main =
putStrLn $ show $
foldl1' (\(x1,x2) (y1,y2) -> if (x2 >= y2) then (x1, x2) else (y1, y2)) $! (assocs collatz_array)
编辑:
我现在还使用未装箱的可变数组完成了一个版本。它仍然比 C++ 版本慢 5 倍,但有了显着的改进。代码在ideonehere。
我想知道对可变数组版本的改进,使其更接近 C++ 版本。
【问题讨论】:
-
仅供参考,使用
-fllvm进行编译可将我的机器性能提高约 10%。 -
您的
seq没有区别;你的两个函数在i中都很严格。 GHC 以前在 32 位平台上 64 位算术很差劲,但我不知道你用的是什么平台。 -
不能解释您的性能问题,但您的 C++(至少 nanothief 发布的内容)和 Haskell 代码都不会产生正确的答案。我无法编译您的 C++,但有一个与您的代码长度大致相同的纯 Haskell 解决方案,它在我的机器上快 25% 左右,并产生正确的结果。在这一点上,大约一半的时间看起来像是与启动 Haskell 程序相关的开销。
-
@PhilipJF 代码在多大程度上没有产生正确的结果?请注意,Clinton 使用了稍微不同的步骤,即对于奇数
n,他直接转到(3*n+1)/2,而不是为此采取两个步骤。因此他得到不同的链长度,但最长链的起点是相同的。 -
@DanielFischer 没错,问题描述描述了链长,其中 (3n+1)/2 将长度增加 2。他的起点正确,但长度错误
标签: haskell optimization