Tôi đang cố gắng viết giải pháp brute-force cho Project Euler Problem #145 và tôi không thể chạy giải pháp của mình trong vòng chưa đầy 1 phút 30 giây.Làm cách nào để tối ưu hóa vòng lặp có thể hoàn toàn nghiêm ngặt
(Tôi biết có nhiều giải pháp cắt ngắn và thậm chí cả giấy và bút chì; vì mục đích của câu hỏi này tôi không xem xét những câu hỏi đó).
Trong phiên bản tốt nhất tôi đã đưa ra cho đến nay, hồ sơ cho thấy phần lớn thời gian được sử dụng trong foldDigits
. Chức năng này không cần phải lười biếng chút nào, và tâm trí của tôi phải được tối ưu hóa thành một vòng lặp đơn giản. Như bạn có thể thấy tôi đã cố gắng thực hiện các bit khác nhau của chương trình một cách nghiêm ngặt.
Vì vậy, câu hỏi của tôi là: mà không thay đổi thuật toán tổng thể, có cách nào để đưa thời gian thực hiện của chương trình này xuống mốc phụ không?
(Hoặc nếu không, là có một cách để thấy rằng các quy tắc ứng foldDigits
được như tối ưu nhất có thể?)
-- ghc -O3 -threaded Euler-145.hs && Euler-145.exe +RTS -N4
{-# LANGUAGE BangPatterns #-}
import Control.Parallel.Strategies
foldDigits :: (a -> Int -> a) -> a -> Int -> a
foldDigits f !acc !n
| n < 10 = i
| otherwise = foldDigits f i d
where (d, m) = n `quotRem` 10
!i = f acc m
reverseNumber :: Int -> Int
reverseNumber !n
= foldDigits accumulate 0 n
where accumulate !v !d = v * 10 + d
allDigitsOdd :: Int -> Bool
allDigitsOdd n
= foldDigits andOdd True n
where andOdd !a d = a && isOdd d
isOdd !x = x `rem` 2 /= 0
isReversible :: Int -> Bool
isReversible n
= notDivisibleByTen n && allDigitsOdd (n + rn)
where rn = reverseNumber n
notDivisibleByTen !x = x `rem` 10 /= 0
countRange acc start end
| start > end = acc
| otherwise = countRange (acc + v) (start + 1) end
where v = if isReversible start then 1 else 0
main
= print $ sum $ parMap rseq cr ranges
where max = 1000000000
qmax = max `div` 4
ranges = [(1, qmax), (qmax, qmax * 2), (qmax * 2, qmax * 3), (qmax * 3, max)]
cr (s, e) = countRange 0 s e
Bạn đang chạy bao nhiêu lõi? – ErikR
đó là Core-i5-760, vì vậy bốn lõi. Tôi biết khó mã hóa các phạm vi trong ứng dụng là một chút icky, nhưng nó làm cho sự song đối một chút rõ ràng hơn. – stusmith