2010-10-17 8 views
5

Dla następnego kodu:Clojure GC przekroczenie limitu górny ocena lazy, sekwencja PI

(ns clojure101.series) 

(defn avg [[x y]] (/ (+ x y) 2)) 

(defn avg-damp 
    [seq] 
    (map avg (partition 2 seq))) 

(defn avg-damp-n 
    [n] 
    (apply comp (repeat n avg-damp))) 

(defn sums 
    [seq] 
    (reductions + seq)) 

(defn Gregory-Leibniz-n 
    [n] 
    (/ (Math/pow -1 n) (inc (* 2 n)))) 

(def Gregory-Leibniz-pi 
    (map #(* 4 (Gregory-Leibniz-n %)) (iterate inc 0))) 

(println (first ((avg-damp-n 10) (sums Gregory-Leibniz-pi)))) 

uzyskać "przekroczenie limitu GC górny" błąd dla N = 20. Jak mogę to naprawić?

UPDATE: Zmieniłem funkcję Średnia wilgotne-n

(defn avg-damp-n 
    [n seq] 
    (if (= n 0) seq 
     (recur (dec n) (avg-damp seq)))) 

teraz mogę dostać numer dla n = 20

(time 
(let [n 20] 
    (println n (first (avg-damp-n n (sums Gregory-Leibniz-pi)))))) 

20 3.141593197943081 
"Elapsed time: 3705.821263 msecs" 

UPDATE 2 Naprawiłem jakiś błąd i teraz działa dobrze:

(ns clojure101.series) 

(defn avg [[x y]] (/ (+ x y) 2)) 

(defn avg-damp 
    [seq] 
    (map avg (partition 2 1 seq))) 

(defn avg-damp-n 
    [n] 
    (apply comp (repeat n avg-damp))) 

(defn sums 
    [seq] 
    (reductions + seq)) 

(defn Gregory-Leibniz-n 
    [n] 
    (/ (int (Math/pow -1 n)) (inc (* 2 n)))) 

(def Gregory-Leibniz-pi 
    (map #(* 4 (Gregory-Leibniz-n %)) (range))) 

; π = 3.14159265358979323846264338327950288419716939937510... 

(time 
(let [n 100] 
    (println n (double (first ((avg-damp-n n) (sums Gregory-Leibniz-pi))))))) 

WYJŚCIE:

100 3.141592653589793 
"Elapsed time: 239.253227 msecs" 

Odpowiedz

2

Hmm ... To działa dla mnie. Testowane z Clojure 1.2 na Windows XP.

user=> (defn avg 
     [xs & {:keys [n] :or {n 2}}] 
     (/ (reduce + xs) n)) 
#'user/avg 
user=> (defn Gregory-Leibniz-n 
     [n] 
     (/ (Math/pow -1 n) (inc (+ n n)))) 
#'user/Gregory-Leibniz-n 
user=> (->> (range) 
     (map #(* 4 (Gregory-Leibniz-n %))) 
     (reductions +) 
     (partition 20) 
     (map #(avg % :n 20)) 
     first 
     println) 
3.1689144018345354 

Czy to właściwa odpowiedź? Nie znam tej rekursji Gregory'ego-Leibniza, więc nie jestem pewien, czy to prawda.

Jeden punkt, który zauważyłem: Próbujesz być zbyt sprytny. Mianowicie twój avg-damp-n układa lazy seq na leniwych sekw. Ponieważ możesz wtyczać dowolne wartości n, , wcześniej lub później napotkasz takie przepełnienia stosów dla dużego w takim scenariuszu w . Jeśli istnieje proste rozwiązanie, powinieneś wybrać opcję . Nie jestem pewien, czy to jest twój rzeczywisty problem. (Jak powiedziałem: dość unhelpfully to działa na mnie.)

+1

Biorąc pod uwagę to ma rozwiązać PI, I don” Uważam, że to właściwa odpowiedź.;) –

+0

@ataggert Masz punkt tam. ;) (Mała edycja: Ale może nadal być liczbą, której OP oczekuje ...) (I oczywiście z tą zmianą powyższe działanie już nie działa). – kotarak

2

Przede wszystkim spróbuj głupie rozwiązanie, które działa: zwiększyć przestrzeń sterty Java.

;in your clojure launch script 
java -Xmx2G ...other options... 

Jest jedna część programu, który nie jest leniwy w partycji, ale zmieniając go tak, że jest leniwy (pozbywając się wezwanie do count) wciąż daje mi OutOfMemoryError dla domyślnego rozmiaru sterty. Wymiana zręczność AVG wilgotne-N o średniej redukcji, w przeliczeniu na

(take (integer-exponent 2 20) seq) 

nadal powoduje OutOfMemoryError. Patrząc na źródło wszystkiego, czego nie widzę, nie widzę innych rzeczy, które wyglądają tak, jakby powinny być kupą sterty.

3

Jak kotarak stwierdzono, Układanie leniwych nast jest na leniwych nast wydaje się zupełnie nieefektywne w odniesieniu do GC. Mogłem odtworzyć ten problem w powolnym systemie atomowym. Zobacz także:

Error java.lang.OutOfMemoryError: GC overhead limit exceeded

Dla mnie Gregory-Leibniz PI caclulation przekształca się bezpośrednio do tego kodeksu Clojure, który wykorzystuje tylko jeden leniwy sekwencję:

(defn Gregory-Leibniz-pi [n] 
    (->> (range n) 
     (map (fn [n] (/ (Math/pow -1 n) (inc (* 2 n))))) 
     (apply +) 
     (* 4)))