Ich versuche, eine Brute-Force-Lösung auf Project Euler Problem #145 zu schreiben, und ich kann meine Lösung nicht in weniger als etwa 1 Minute 30 Sekunden ausgeführt werden.Wie optimiere ich eine Schleife, die vollständig streng sein kann
(Ich weiß, es gibt verschiedene Abkürzungen und sogar Papier-und-Stift-Lösungen; für den Zweck dieser Frage denke ich nicht über diese).
In der besten Version, die ich bis jetzt gefunden habe, zeigt Profiling, dass die meiste Zeit in foldDigits
verbracht wird. Diese Funktion muss überhaupt nicht faul sein und sollte für mich zu einer einfachen Schleife optimiert werden. Wie Sie sehen können, habe ich versucht, verschiedene Teile des Programms strikt zu machen.
Also meine Frage ist: ohne den Gesamtalgorithmus zu ändern, gibt es eine Möglichkeit, die Ausführungszeit dieses Programms auf die Sub-Minuten-Marke herunter zu bringen?
(oder wenn nicht, gibt es eine Möglichkeit, um zu sehen, dass der Code von foldDigits
so weit wie möglich optimiert ist?)
-- 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
Wie viele Kerne betreiben Sie es? – ErikR
ist es ein Core-i5-760, also vier Kerne. Ich weiß, dass die Bereiche in der Anwendung hart zu kodieren ist ein bisschen eklig, aber es machte die Parallelität ein wenig klarer. – stusmith