2010-10-17 17 views
5

Para el siguiente código:Clojure: límite gc overhead superado, la evaluación perezosa, secuencia 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)))) 

consigo "límite gc overhead excedido" error para n = 20. ¿Cómo puedo solucionar esto?

ACTUALIZACIÓN: I cambió función avg-húmedo-n

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

ahora puedo obtener el número de 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" 

ACTUALIZACIÓN 2 I fija algún error y ahora funciona bien:

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

SALIDA:

100 3.141592653589793 
"Elapsed time: 239.253227 msecs" 

Respuesta

2

Hmm ... Esto funciona para mí. Probado con Clojure 1.2 en 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 

¿Es esa la respuesta correcta? No sé esta recursividad de Gregory-Leibniz, así que estoy no estoy seguro de si esto es correcto.

Un punto que noté: Estás tratando de ser demasiado inteligente. A saber, su avg-damp-n apila lazy seq en lazy seq. Como puede agregar valores arbitrarios de n, , tarde o temprano también experimentará desbordamientos de pila para n grande en tal escenario. Si hay una solución sencilla, debe preferir . Aunque no estoy seguro de que este sea su problema real. (Como ya he dicho: en lugar inútilmente que funciona para mí.)

+1

Teniendo en cuenta esto se supone que resolver a Pi, I don' Creo que esa es la respuesta correcta.;) –

+0

@ataggert Tienes punto allí. ;) (Pequeña edición: Pero aún puede ser el número que OP espera ...) (Y, por supuesto, con el cambio '(partición 2 1 ...) 'de lo anterior ya no funciona). – kotarak

2

En primer lugar, intente la solución estúpida que funciona: aumentar su espacio de montón de Java.

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

Hay una parte del programa que no es perezoso en la partición, pero cambiando de modo que es perezoso (por deshacerse de una llamada a count) todavía me da un OutOfMemoryError para el tamaño de la pila por defecto. Sustitución de la inteligencia de AVG-húmedo-n con un promedio calculado-reducir en

(take (integer-exponent 2 20) seq) 

todavía provoca una OutOfMemoryError. Mirando la fuente de todo lo demás, no veo otras cosas que parezcan consumir mucho.

3

Como kotarak se ha dicho, el apilamiento de Lazy seq sobre Lazy seq parece bastante ineficiente con respecto al GC. Podría reproducir este problema en un sistema de átomos lentos. Ver también:

Error java.lang.OutOfMemoryError: GC overhead limit exceeded

Para mí Gregory-Leibniz PI caclulation transforma directamente en este Código Clojure que utiliza sólo una secuencia perezosa:

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