Daniel Lyons <[email protected]> writes:

Hi Daniel,

> In your particular case I think you might want to take a look at the
> source code in the contrib project which implements a lazy list of
> primes:
>
> http://code.google.com/p/clojure-contrib/source/browse/trunk/src/clojure/contrib/lazy_seqs.clj

I came up with another approach on lazily calculating primes using the
Miller Rabin algorithm.  Calculating the primes < 100.000 akes about 12
seconds on my 2.2 GHz dual core.  Here it is:

--8<---------------cut here---------------start------------->8---
(ns de.tsdh.math.primes
  (:use [clojure.contrib [math :only [expt]]
         [test-is :only [deftest is]]
         [def :only [defvar defvar-]]]))

(defvar *pseudo-accuracy* 10
  "The chances that prime? returns true for a composite is (expt 4 (* -1
*pseudo-accuracy*)).")

(defn factorize-out
  "Factorizes out all x factors from n.
Examples:
  (factorize-out 10 2) ==> {:exponent 1, :rest 5}, because 2^1 * 5 = 10
  (factorize-out 90 3) ==> {:exponent 2, :rest 10}, because 3^2 * 10 = 90"
  [n x]
  (loop [acc n exp 0]
    (if (= 0 (mod acc x))
      (recur (/ acc x) (inc exp))
      (hash-map :exponent exp :rest acc))))

(defn expt-mod
  "Equivalent to (mod (expt n e) m), but faster.
http://en.wikipedia.org/wiki/Modular_exponentiation#An_efficient_method:_the_right-to-left_binary_algorithm";
  [n e m]
  (loop [r 1, b n, e e]
    (if (= e 0)
      r
      (recur (if (odd? e)
               (mod (* r b) m)
               r)
             (mod (expt b 2) m)
             (bit-shift-right e 1)))))

(defn prime?
  "Checks if n is a prime using the Miller-Rabin pseudo-primality test.  Also
see *pseudo-accuracy*."
  [n]
  (cond
    (< n 2)   false
    (= n 2)   true
    (even? n) false
    :else (let [m (factorize-out (dec n) 2)
                d (:rest m)
                s (:exponent m)]
            (loop [k 1]
              (if (> k *pseudo-accuracy*)
                true
                (let [a (+ 2 (rand-int (- n 4)))
                      x (expt-mod a d n)]
                  (if (or (= x 1) (= x (dec n)))
                    (recur (inc k))
                    (if (loop [r 1
                               x (expt-mod x 2 n)]
                          (cond
                           (or (= x 1) (>  r (dec s)))  false
                           (= x (dec n))                true
                           :else (recur (inc r) (mod (* x x) n))))
                      (recur (inc k))
                      false))))))))

(defn next-prime
  "Returns the next prime greater than n."
  [n]
  (cond
    (< n 2) 2
    :else (loop [n (inc n)]
            (if (prime? n)
              n
              (recur (inc n))))))

(defn primes
  "Returns a lazy sequence of prime numbers"
  []
  (iterate next-prime 2))
--8<---------------cut here---------------end--------------->8---

Bye,
Tassilo

--~--~---------~--~----~------------~-------~--~----~
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