2010-10-17 4 views
5

für den nächsten Code:Clojure: gc Obergrenze überschritten, lazy evaluation, pi-Sequenz

(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)))) 

I get "gc Kopfgrenze überschritten" Fehler für n = 20. Wie kann ich das beheben?

UPDATE: Ich änderte avg-feucht-n-Funktion

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

jetzt kann ich Nummer für 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 ich einige Fehler behoben und jetzt es funktioniert ganz gut:

(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))))))) 

OUTPUT:

100 3.141592653589793 
"Elapsed time: 239.253227 msecs" 

Antwort

2

Hmm ... Das funktioniert für mich. Getestet mit Clojure 1.2 unter 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 

Ist das die richtige Antwort? Ich kenne diese Gregory-Leibniz-Rekursion nicht, also bin ich nicht sicher, ob das korrekt ist.

Ein Punkt, den ich festgestellt habe: Sie versuchen, zu schlau zu sein. Nämlich Ihre avg-damp-n Stacks Lazy Seq auf Lazy Seq. Da Sie beliebige Werte von n, Plugin pluginieren können, werden Sie früher oder später auch Stapelüberläufe für große n in ein solches Szenario erleben. Wenn es eine unkomplizierte Lösung gibt, sollten Sie es bevorzugen. Ich bin mir nicht sicher, ob das dein tatsächliches Problem ist. (Wie ich sagte: eher nicht hilfreich es funktioniert für mich.)

+1

dies bedenkt, soll Pi zu lösen, I don‘ Das ist die richtige Antwort.;) –

+0

@ataggert Du hast dort hin gedeutet. ;) (Kleiner Schnitt: Aber es darf immer noch die Zahl sein, die das OP erwartet ...) (Und natürlich mit der '(Partition 2 1 ...)' Änderung das obige funktioniert nicht mehr.) – kotarak

2

Zunächst einmal versuchen, die dumme Lösung, die funktioniert: Ihr Java-Heap-Speicher erhöhen.

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

Es ist ein Teil des Programms, das in der Partition nicht faul ist, aber es ändert mich so, dass er faul ist (durch einen Aufruf count loszuwerden) gibt mir noch einen OutOfMemoryError für die Standard-Heap-Größe. Ersetzen der Klugheit von avg-feucht-n mit einem reduzieren berechneten Durchschnitt auf

(take (integer-exponent 2 20) seq) 

verursacht noch eine OutOfMemoryError. Wenn ich die Quelle von allem anderen betrachte, sehe ich keine anderen Dinge, die aussehen, als sollten sie Heap verbrauchen.

3

Wie kotarak festgestellt, scheint die Stapelung von Lazy Seq auf faul seq's ziemlich ineffizient in Bezug auf GC. Ich könnte dieses Problem auf einem langsamen Atomsystem reproduzieren. Siehe auch:

Error java.lang.OutOfMemoryError: GC overhead limit exceeded

Für mich Gregory-Leibniz PI caclulation direkt diesem Clojure-Code verwandelt sich in die nur eine faule Sequenz verwendet:

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