gpt4 book ai didi

haskell - GHC优化: Collatz conjecture

转载 作者:行者123 更新时间:2023-12-03 15:30:47 25 4
gpt4 key购买 nike

我已经为 Project Euler's Challenge 14 编写了代码, 在这两个 HaskellC++ (ideone链接)。他们都记得他们之前在数组中所做的任何计算。

使用 ghc -O2g++ -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 倍,但有了显着的改进。代码在ideone here .

我想知道对可变数组版本的改进,使其更接近 C++ 版本。

最佳答案

您的(可变数组)代码存在一些问题:

  • 您使用折叠来查找最大链长度,因为必须将数组转换为关联列表,这需要时间和分配 C++ 版本不需要。
  • 您使用 evendiv用于测试resp除以2。这些很慢。 g++ 将这两种操作都优化为更快的位操作(至少在据称更快的平台上),但 GHC 还没有进行这些低级优化,所以目前,它们必须手动完成.
  • 您使用 readArraywriteArray .在 C++ 代码中未完成的额外边界检查也需要时间,一旦处理了其他问题,这相当于运行时间的很大一部分(我的盒子上大约 25%),因为已经完成算法中有很多读写操作。

  • 将其纳入实现,我得到
    import Data.Array.ST
    import Data.Array.Base
    import Control.Monad.ST
    import Data.Bits

    collatz_array :: ST s (STUArray s Int Int)
    collatz_array = do
    let upper = 10000000
    arr <- newArray (0,upper) 0
    unsafeWrite arr 2 1
    let check i
    | upper < i = return arr
    | i .&. 1 == 0 = do
    l <- unsafeRead arr (i `shiftR` 1)
    unsafeWrite arr i (l+1)
    check (i+1)
    | otherwise = do
    let j = (3*i+1) `shiftR` 1
    find k l
    | upper < k = find (next k) $! l+1
    | k < i = do
    m <- unsafeRead arr k
    return (m+l)
    | otherwise = do
    m <- unsafeRead arr k
    if m == 0
    then do
    n <- find (next k) 1
    unsafeWrite arr k n
    return (n+l)
    else return (m+l)
    where
    next h
    | h .&. 1 == 0 = h `shiftR` 1
    | otherwise = (3*h+1) `shiftR` 1
    l <- find j 1
    unsafeWrite arr i l
    check (i+1)
    check 3

    collatz_max :: ST s (Int,Int)
    collatz_max = do
    car <- collatz_array
    (_,upper) <- getBounds car
    let find w m i
    | upper < i = return (w,m)
    | otherwise = do
    l <- unsafeRead car i
    if m < l
    then find i l (i+1)
    else find w m (i+1)
    find 1 0 2

    main :: IO ()
    main = print (runST collatz_max)

    以及时间(均为 1000 万):
    $ time ./cccoll
    8400511 429

    real 0m0.210s
    user 0m0.200s
    sys 0m0.009s
    $ time ./stcoll
    (8400511,429)

    real 0m0.341s
    user 0m0.307s
    sys 0m0.033s

    这看起来还不错。

    重要提示:该代码仅适用于 64 位 GHC(因此,特别是在 Windows 上,您需要 ghc-7.6.1 或更高版本,以前的 GHC 即使在 64 位 Windows 上也是 32 位),因为中间链元素超过 32 位范围.在 32 位系统上,必须使用 Integer或 64 位整数类型( Int64Word64 )用于跟随链,以极大的性能成本,因为原始的 64 位操作(算术和移位)被实现为对 32- 中的 C 函数的外部调用位 GHC(快速外呼,但仍比直接机器操作慢得多)。

    关于haskell - GHC优化: Collatz conjecture,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10876110/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com