Hi

On 28 August 2010 02:25, neveu <[email protected]> wrote:
> I implemented the "Flavius Josephus" algorithm from Programming Praxis
> in Clojure using loop/recur. My first version looked like this:
>
> (defn rotate-left
>  ([ln n m]
>     (take n (drop (dec m) (cycle ln))))
>  ([ln m] (rotate-left ln (count ln) m)))
>
> (defn josephus3 [N M] ;; execute every mth soldier
>  (loop [soldiers (range N)
>         m M
>         deceased '()]
>    (let [n (count soldiers)]
>      (cond
>     (zero? n) deceased
>     true (let [r (rotate-left soldiers n m)
>                dead (cons (first r) deceased)
>                survivors (rest r)]
>            (recur survivors m dead))))))
>
> This works fine, but I don't really need to count the soldiers every
> pass, it always decreases by 1. So I wrote this version in which n is
> one of the loop parameters:
>
> (defn josephus4 [N M] ;; execute every mth soldier
>  (loop [soldiers (range N)
>         n N
>         m M
>         deceased '()]
>    (cond
>     (zero? n) deceased
>     true (let [r (rotate-left soldiers n m)
>                dead (cons (first r) deceased)
>                survivors (rest r)]
>            (recur survivors (dec n)  m dead)))))
>
> Both work for small N (e.g. 41) but the second one fails for large
> (41000) N with a stack overflow.
> What am I missing here?

It seems to be the lazyness of rotate-left that causes it.  Not sure
why it doesn't affect josephus3, but breaks josephus4, though.

I tried starting java with a 60k thread stack size to make it easier
to see the problem:

java -Xss60k ...

Then this fails with an n as low as 100:

(defn josephus5 [N M] ;; execute every mth soldier
  (loop [soldiers (range N)
         n N
         m M
         deceased []]
    (cond
      (zero? n) deceased
      :else (let [r (rotate-left soldiers n m)
                  dead (conj deceased (first r))
                  survivors (rest r)]
              (recur survivors (dec n) m dead)))))

but this works (obviously with the wrong results):

(defn josephus6 [N M] ;; execute every mth soldier
  (loop [soldiers (range N)
         n N
         m M
         deceased []]
    (cond
      (zero? n) deceased
      :else (let [r soldiers
                  dead (conj deceased (first r))
                  survivors (rest r)]
              (recur survivors (dec n) m dead)))))

I then changed rotate-left and updated josephus as follows:

(defn rotate-left2
  ([ln n m]
   (doall (take n (drop (dec m) (cycle ln)))))
  ([ln m] (rotate-left ln (count ln) m)))

(defn josephus7 [N M] ;; execute every mth soldier
  (loop [soldiers (range N)
         n N
         m M
         deceased []]
    (cond
      (zero? n) deceased
      :else (let [r (rotate-left2 soldiers n m)
                  dead (conj deceased (first r))
                  survivors (rest r)]
              (recur survivors (dec n) m dead)))))

and that seems to work.

-- 
Michael Wood <[email protected]>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to