2015-12-17 44 views
5

Próbuję przetestować następującą funkcję Faktoryzacji ale to wysadzenie dla dużych liczb pierwszych:Recursion przelewowy użyciu Trampolining

(defn divides? [N n] 
    (zero? (mod N n))) 

(defn f-reduce [n f & {:keys [expt] :or {expt 0}}] 
    (if (divides? n f) (f-reduce (/ n f) f :expt (inc expt)) 
        (if (zero? expt) [n []] [n [f expt]]))) 

(defn _factors [n f known-fs] 
    (let [[m fs] (f-reduce n f)] 
    (if (> f (Math/sqrt m)) 
     (cond (and (empty? fs) (= m 1)) known-fs 
      (empty? fs)    (concat known-fs [m 1]) 
      (= m 1)     (concat known-fs [f (last fs)]) 
      true      (concat known-fs [m (last fs)])) 
     #(_factors m (+ 2 f) (concat known-fs fs)))))) 

(defn factors 
    "returns the prime factors of n in form: p_0 expt_0 p_1 expt_1 ... p_m expt_m, 
    where p_i denotes ith prime factor, and expt_i denotes exponent of p_i" 
    [n] 
    (let [[m fs] (f-reduce n 2)] 
    (trampoline (_factors m 3 fs)))) 

który na każdym kroku rekurencyjnego próbuje zmniejszyć liczbę n do jakiegoś produktu p^k m.

Jak rozumiem, trampolina ma rozwiązać problem poprzez powrocie funkcji, które następnie wywołuje trampolina (powrót innej funkcji) i tak dalej, obraz stos patrząc coś takiego:

|fn 1| --> |fn 2| -- ... --> |fn n| 

w przeciwieństwie do non-tail rekurencyjne

|fn 1| --> |fn 1|fn 2| -- .. --> |fn 1|fn 2| ... |fn n-k| BOOM| 

Ale wejście do czynników będąc 12424242427 uzyskać:

java.lang.StackOverflowError: null 
at clojure.lang.LazySeq.seq (LazySeq.java:49) 
    clojure.lang.RT.seq (RT.java:507) 
    clojure.core/seq (core.clj:137) 
    clojure.core$concat$fn__4215.invoke (core.clj:691) 
    clojure.lang.LazySeq.sval (LazySeq.java:40) 
    clojure.lang.LazySeq.seq (LazySeq.java:49) 
    clojure.lang.RT.seq (RT.java:507) 
    clojure.core/seq (core.clj:137) 
    clojure.core$concat$fn__4215.invoke (core.clj:691) 
    clojure.lang.LazySeq.sval (LazySeq.java:40) 
    clojure.lang.LazySeq.seq (LazySeq.java:49) 
    clojure.lang.RT.seq (RT.java:507) 
    clojure.core/seq (core.clj:137) 
    clojure.core$concat$fn__4215.invoke (core.clj:691) 
    clojure.lang.LazySeq.sval (LazySeq.java:40) 
    clojure.lang.LazySeq.seq (LazySeq.java:49) 
    clojure.lang.RT.seq (RT.java:507) 
    clojure.core/seq (core.clj:137) 
    clojure.core$concat$fn__4215.invoke (core.clj:691) 
    clojure.lang.LazySeq.sval (LazySeq.java:40) 
    clojure.lang.LazySeq.seq (LazySeq.java:49) 

Czego mi brakuje? (Wiem, że ten algorytm nie jest idealny, poprawi to całkowicie dla mnie)

+0

próbowałem wydrukować wynik '(println (czynniki 12424242427))' a ja się go normalnie: '(12424242427 1)'. dziwne –

+0

hmm ... dziwne, bo co jest warte, biegnę w emacs z cydrem (jeśli to robi różnicę do stosu dostępnego dla mnie!) – HexedAgain

+0

@RomanMakhlin, z którą wersją Clojure? Mogę odtworzyć błąd w "repl lein" (Clojure 1.6.0). –

Odpowiedz