我写了一个针对Project Euler挑战14的代码,分别使用Haskell和C++编写(ideone链接)。它们都会在数组中记住之前做过的计算。
使用ghc -O2
和g++ -O3
编译后,C++版本比Haskell版本快10-15倍。
虽然我知道Haskell版本可能运行得比较慢,并且Haskell是一种更好的编程语言,但知道一些可以使Haskell版本运行更快的代码更改将会很不错(最好是能够达到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倍,但是有了显著的改进。代码可以在ideone上这里找到。
我想知道如何改进可变数组版本,使其更接近C++版本。
-fllvm
编译可以在我的电脑上提高大约10%的性能。 - Greg E.seq
没有任何作用;你的两个函数都在i
上是严格的。 GHC 曾经在 32 位平台上进行 64 位算术运算时表现非常糟糕,但我不知道你使用的是什么平台。 - augustssn
,他直接转到(3*n+1)/2
,而不是采取两个步骤。因此,他得到了不同的链长度,但最长链的起始点是相同的。 - Daniel Fischer