在解决问题时,我必须计算一个数字的除数。我有两个实现可以为给定数字生成所有除数 > 1。
首先是使用简单的递归:
divisors :: Int64 -> [Int64]
divisors k = divisors' 2 k
where
divisors' n k | n*n > k = [k]
| n*n == k = [n, k]
| k `mod` n == 0 = (n:(k `div` n):result)
| otherwise = result
where result = divisors' (n+1) k
第二个使用 Prelude 中的列表处理函数:
divisors2 :: Int64 -> [Int64]
divisors2 k = k : (concatMap (\x -> [x, k `div` x]) $!
filter (\x -> k `mod` x == 0) $!
takeWhile (\x -> x*x <= k) [2..])
我发现第一个实现更快(我打印了返回的整个列表,因此没有部分结果由于懒惰而未被评估)。这两种实现产生不同顺序的除数,但这对我来说不是问题。(事实上,如果 k 是一个完美的平方,那么在第二个实现中平方根会被输出两次——这也不是问题)。
一般来说,这种递归实现在 Haskell 中更快吗?另外,我将不胜感激任何使这些代码更快的指针。谢谢!
编辑:
这是我用来比较这两种实现的性能的代码:https ://gist.github.com/3414372
这是我的计时测量:
使用严格评估的除数 ($!)
$ ghc --make -O2 div.hs
[1 of 1] Compiling Main ( div.hs, div.o )
Linking div ...
$ time ./div > /tmp/out1
real 0m7.651s
user 0m7.604s
sys 0m0.012s
使用带有惰性求值 ($) 的除数 2:
$ ghc --make -O2 div.hs
[1 of 1] Compiling Main ( div.hs, div.o )
Linking div ...
$ time ./div > /tmp/out1
real 0m7.461s
user 0m7.444s
sys 0m0.012s
使用函数除数
$ ghc --make -O2 div.hs
[1 of 1] Compiling Main ( div.hs, div.o )
Linking div ...
$ time ./div > /tmp/out1
real 0m7.058s
user 0m7.036s
sys 0m0.020s