Obecnie pracuję nad project euler problem 14.Projekt Euler 14: wydajność w porównaniu do C i zapamiętywanie
Rozwiązałem go przy użyciu słabo zakodowanego programu, bez konieczności zapamiętywania, które trwało przez 5 sekund (patrz edycja), które trwało .
Oto ona:
step :: (Integer, Int) -> Integer -> (Integer, Int)
step (i, m) n | nextValue > m = (n, nextValue)
| otherwise = (i, m)
where nextValue = syr n 1
syr :: Integer -> Int -> Int
syr 1 acc = acc
syr x acc | even x = syr (x `div` 2) (acc + 1)
| otherwise = syr (3 * x + 1) (acc + 1)
p14 = foldl step (0, 0) [500000..999999]
Moje pytanie jest o kilka komentarzy w wątku związanego z tym problemem, gdzie wymieniono czasy wykonania < 1 s dla programów jak następuje (kod C, kredytów do projektu Euler forum użytkownik ix kodu - uwaga: nie sprawdzałem, że czas realizacji jest w rzeczywistości, jak wymieniono):
#include <stdio.h>
int main(int argc, char **argv) {
int longest = 0;
int terms = 0;
int i;
unsigned long j;
for (i = 1; i <= 1000000; i++) {
j = i;
int this_terms = 1;
while (j != 1) {
this_terms++;
if (this_terms > terms) {
terms = this_terms;
longest = i;
}
if (j % 2 == 0) {
j = j/2;
} else {
j = 3 * j + 1;
}
}
}
printf("longest: %d (%d)\n", longest, terms);
return 0;
}
dla mnie thos Programy e są trochę takie same, mówiąc o algorytmie.
Więc zastanawiam się, dlaczego istnieje tak duża różnica? Czy istnieje jakaś różnica między naszymi dwoma algorytmami, które mogą usprawiedliwiać czynnik x6 w wydajności?
BTW, obecnie próbuję zaimplementować ten algorytm za pomocą memoizacji, ale jestem trochę zagubiony co do mnie, jest to łatwiejsze do zrealizowania w imperatywnym języku (i nie manipuluję jeszcze monadami, więc nie mogę użyj tego paradygmatu). Więc jeśli masz dobry tutorial, który pasuje początkującym do nauki zapamiętania, będę zadowolony (ci, których spotkałem, nie byli wystarczająco szczegółowi lub poza moją ligą).
Uwaga: Doszedłem do paradygmatu deklaratywnego przez Prolog i wciąż znajduję się w bardzo wczesnym procesie odkrywania Haskella, więc mógłbym pominąć ważne rzeczy.
Uwaga 2: wszelkie ogólne porady dotyczące mojego kodu są mile widziane.
EDIT: dzięki pomocy delnan, w skompilowany program, a teraz pracuje w 5 sekund, więc patrzę głównie na wskazówki, memoization NOW (nawet jeśli wyobrażenia o istniejącej luki x6 są nadal mile widziane).
Cóż, zamienianie 'ghci' na' ghc -O' powinno być nie myślenia i jest zobowiązane do zmniejszenia luki. Bez względu na to, jak skuteczna jest ta metoda, wypróbowanie jej jest prawdopodobnie dobrym pomysłem, choćby po to, by odpowiedzieć osławionym "co próbowaliście?" komentarz;) Nie wspominając o tym, że łatwiej i szybciej wypróbować niż przynieść memo. – delnan
@delnan: Cóż, moim problemem jest to, że wciąż jestem nowy w Haskell i nadal nie patrzyłem, jak poprawnie skompilować program. A dokładniej, spojrzałem i zobaczyłem, że 'do' zostało użyte i myślałem, że wrócę do niego później, kiedy będę pracował nad monadami. Ale przeczytałbym to samo zdanie, więc czuję się trochę głupio: p – m09
Aby zacząć, możesz prawdopodobnie uciec z 'main = print p14' i skompilować jako' ghc -O p14.hs' . – delnan