Project Euler #10 (sum of primes less than two million) in Clojure











up vote
2
down vote

favorite












I'm new to Clojure and using some Project Euler problems to familiarize myself with the language's capabilities. Problem #10 asks to find the sum of all primes less than two million.



I wanted to solve this problem by building a generalized Sieve of Eratosthenes, then adding up all the primes:



(defn sieve [size]
(-> (reduce (fn [prev i]
(if (prev i)
(vec (reduce #(assoc %1 %2 false)
prev
(range (+ i i) size i)))
prev))
(vec (repeat size true))
(range 2 (-> size Math/sqrt int inc)))
vec
(assoc 0 false)
(assoc 1 false)))

(time
(let [limit 2000000
s (sieve limit)]
(reduce #(+ %1 (if (s %2) %2 0))
0 (range limit))))


That works, but takes over 14 seconds when run from an already "hot" REPL. For comparison, I did a simple Java implementation:



import java.util.Arrays;
import java.lang.Math;

public class P10 {
public static void main(String args) {
int size = 2000000;

boolean sieve = new boolean[size];

Arrays.fill(sieve, true);
sieve[0] = false;
sieve[1] = false;

for (int i = 2; i < (1 + Math.sqrt(size)); i++) {
if (sieve[i]) {
for (int j = i + i; j < size; j += i) {
sieve[j] = false;
}
}
}

long sum = 0;
for (int i = 0; i < size; i++) {
if (sieve[i]) sum += (long) i;
}

System.out.println(sum);
}
}


Which runs in about 0.7 seconds from the command line. (Incidentally, my Java experience isn't very deep either--does that include JVM startup?)



So I thought maybe the problem with the "pure" (?) Clojure version is the creation/reliance on Clojure's vectors. So my idea was to rework the Clojure version to use Java's mutable array:



(defn sieve [size]
(-> (let [ar (to-array (repeat size true))]
(dorun (map (fn [i]
(when (aget ar i)
(dorun (map (fn [j] (aset ar j false))
(range (+ i i) size i)))))
(range 2 (-> size Math/sqrt int inc))))
ar)
vec
(assoc 0 false)
(assoc 1 false)))


But that takes more than 3.5 seconds.



At this point, I'm not so interested in implementing fancy things like bit-packing, I'm just trying to reach performance parity with the "traditional" Java implementation. What am i doing "wrong" in my Clojure that makes it "non-competitive" with the Java version?



Also, any other tips/hints/criticisms regarding Clojure style?










share|improve this question




























    up vote
    2
    down vote

    favorite












    I'm new to Clojure and using some Project Euler problems to familiarize myself with the language's capabilities. Problem #10 asks to find the sum of all primes less than two million.



    I wanted to solve this problem by building a generalized Sieve of Eratosthenes, then adding up all the primes:



    (defn sieve [size]
    (-> (reduce (fn [prev i]
    (if (prev i)
    (vec (reduce #(assoc %1 %2 false)
    prev
    (range (+ i i) size i)))
    prev))
    (vec (repeat size true))
    (range 2 (-> size Math/sqrt int inc)))
    vec
    (assoc 0 false)
    (assoc 1 false)))

    (time
    (let [limit 2000000
    s (sieve limit)]
    (reduce #(+ %1 (if (s %2) %2 0))
    0 (range limit))))


    That works, but takes over 14 seconds when run from an already "hot" REPL. For comparison, I did a simple Java implementation:



    import java.util.Arrays;
    import java.lang.Math;

    public class P10 {
    public static void main(String args) {
    int size = 2000000;

    boolean sieve = new boolean[size];

    Arrays.fill(sieve, true);
    sieve[0] = false;
    sieve[1] = false;

    for (int i = 2; i < (1 + Math.sqrt(size)); i++) {
    if (sieve[i]) {
    for (int j = i + i; j < size; j += i) {
    sieve[j] = false;
    }
    }
    }

    long sum = 0;
    for (int i = 0; i < size; i++) {
    if (sieve[i]) sum += (long) i;
    }

    System.out.println(sum);
    }
    }


    Which runs in about 0.7 seconds from the command line. (Incidentally, my Java experience isn't very deep either--does that include JVM startup?)



    So I thought maybe the problem with the "pure" (?) Clojure version is the creation/reliance on Clojure's vectors. So my idea was to rework the Clojure version to use Java's mutable array:



    (defn sieve [size]
    (-> (let [ar (to-array (repeat size true))]
    (dorun (map (fn [i]
    (when (aget ar i)
    (dorun (map (fn [j] (aset ar j false))
    (range (+ i i) size i)))))
    (range 2 (-> size Math/sqrt int inc))))
    ar)
    vec
    (assoc 0 false)
    (assoc 1 false)))


    But that takes more than 3.5 seconds.



    At this point, I'm not so interested in implementing fancy things like bit-packing, I'm just trying to reach performance parity with the "traditional" Java implementation. What am i doing "wrong" in my Clojure that makes it "non-competitive" with the Java version?



    Also, any other tips/hints/criticisms regarding Clojure style?










    share|improve this question


























      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      I'm new to Clojure and using some Project Euler problems to familiarize myself with the language's capabilities. Problem #10 asks to find the sum of all primes less than two million.



      I wanted to solve this problem by building a generalized Sieve of Eratosthenes, then adding up all the primes:



      (defn sieve [size]
      (-> (reduce (fn [prev i]
      (if (prev i)
      (vec (reduce #(assoc %1 %2 false)
      prev
      (range (+ i i) size i)))
      prev))
      (vec (repeat size true))
      (range 2 (-> size Math/sqrt int inc)))
      vec
      (assoc 0 false)
      (assoc 1 false)))

      (time
      (let [limit 2000000
      s (sieve limit)]
      (reduce #(+ %1 (if (s %2) %2 0))
      0 (range limit))))


      That works, but takes over 14 seconds when run from an already "hot" REPL. For comparison, I did a simple Java implementation:



      import java.util.Arrays;
      import java.lang.Math;

      public class P10 {
      public static void main(String args) {
      int size = 2000000;

      boolean sieve = new boolean[size];

      Arrays.fill(sieve, true);
      sieve[0] = false;
      sieve[1] = false;

      for (int i = 2; i < (1 + Math.sqrt(size)); i++) {
      if (sieve[i]) {
      for (int j = i + i; j < size; j += i) {
      sieve[j] = false;
      }
      }
      }

      long sum = 0;
      for (int i = 0; i < size; i++) {
      if (sieve[i]) sum += (long) i;
      }

      System.out.println(sum);
      }
      }


      Which runs in about 0.7 seconds from the command line. (Incidentally, my Java experience isn't very deep either--does that include JVM startup?)



      So I thought maybe the problem with the "pure" (?) Clojure version is the creation/reliance on Clojure's vectors. So my idea was to rework the Clojure version to use Java's mutable array:



      (defn sieve [size]
      (-> (let [ar (to-array (repeat size true))]
      (dorun (map (fn [i]
      (when (aget ar i)
      (dorun (map (fn [j] (aset ar j false))
      (range (+ i i) size i)))))
      (range 2 (-> size Math/sqrt int inc))))
      ar)
      vec
      (assoc 0 false)
      (assoc 1 false)))


      But that takes more than 3.5 seconds.



      At this point, I'm not so interested in implementing fancy things like bit-packing, I'm just trying to reach performance parity with the "traditional" Java implementation. What am i doing "wrong" in my Clojure that makes it "non-competitive" with the Java version?



      Also, any other tips/hints/criticisms regarding Clojure style?










      share|improve this question















      I'm new to Clojure and using some Project Euler problems to familiarize myself with the language's capabilities. Problem #10 asks to find the sum of all primes less than two million.



      I wanted to solve this problem by building a generalized Sieve of Eratosthenes, then adding up all the primes:



      (defn sieve [size]
      (-> (reduce (fn [prev i]
      (if (prev i)
      (vec (reduce #(assoc %1 %2 false)
      prev
      (range (+ i i) size i)))
      prev))
      (vec (repeat size true))
      (range 2 (-> size Math/sqrt int inc)))
      vec
      (assoc 0 false)
      (assoc 1 false)))

      (time
      (let [limit 2000000
      s (sieve limit)]
      (reduce #(+ %1 (if (s %2) %2 0))
      0 (range limit))))


      That works, but takes over 14 seconds when run from an already "hot" REPL. For comparison, I did a simple Java implementation:



      import java.util.Arrays;
      import java.lang.Math;

      public class P10 {
      public static void main(String args) {
      int size = 2000000;

      boolean sieve = new boolean[size];

      Arrays.fill(sieve, true);
      sieve[0] = false;
      sieve[1] = false;

      for (int i = 2; i < (1 + Math.sqrt(size)); i++) {
      if (sieve[i]) {
      for (int j = i + i; j < size; j += i) {
      sieve[j] = false;
      }
      }
      }

      long sum = 0;
      for (int i = 0; i < size; i++) {
      if (sieve[i]) sum += (long) i;
      }

      System.out.println(sum);
      }
      }


      Which runs in about 0.7 seconds from the command line. (Incidentally, my Java experience isn't very deep either--does that include JVM startup?)



      So I thought maybe the problem with the "pure" (?) Clojure version is the creation/reliance on Clojure's vectors. So my idea was to rework the Clojure version to use Java's mutable array:



      (defn sieve [size]
      (-> (let [ar (to-array (repeat size true))]
      (dorun (map (fn [i]
      (when (aget ar i)
      (dorun (map (fn [j] (aset ar j false))
      (range (+ i i) size i)))))
      (range 2 (-> size Math/sqrt int inc))))
      ar)
      vec
      (assoc 0 false)
      (assoc 1 false)))


      But that takes more than 3.5 seconds.



      At this point, I'm not so interested in implementing fancy things like bit-packing, I'm just trying to reach performance parity with the "traditional" Java implementation. What am i doing "wrong" in my Clojure that makes it "non-competitive" with the Java version?



      Also, any other tips/hints/criticisms regarding Clojure style?







      performance programming-challenge comparative-review clojure sieve-of-eratosthenes






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited yesterday









      200_success

      127k15149412




      127k15149412










      asked yesterday









      brian_o

      77949




      77949






















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          1
          down vote













          I won't comment on the Java bit because I don't write Java very often. I agree with the other answer though that sqrt should only be called once. Computing the sqrt of a number is relatively expensive.





          First, for Clojure, a baseline on my computer:



          (defn sieve [size]
          (-> (reduce (fn [prev i]
          (if (prev i)
          (vec (reduce #(assoc %1 %2 false)
          prev
          (range (+ i i) size i)))
          prev))
          (vec (repeat size true))
          (range 2 (-> size Math/sqrt int inc)))
          vec
          (assoc 0 false)
          (assoc 1 false)))

          (defn main
          (time
          (let [limit 2000000
          s (sieve limit)]
          (reduce #(+ %1 (if (s %2) %2 0))
          0 (range limit)))))

          ; From REPL
          (main)
          "Elapsed time: 2274.584779 msecs"
          => 142913828922


          I should note that I'm on a crappy M3 Surface Pro 4; not a power machine by a stretch of any definition. If this is taking 14 seconds, you must have something else going on. That's far too long.





          I actually prefer wrapping threading calls in parenthesis, even if they aren't required. I'd write lines such as (-> size Math/sqrt int inc) as (-> size (Math/sqrt) (int) (inc)). I find it helps differentiating between the form being a plain function call, and the threading of a value. The only time I omit them is when I'm golfing.





          Your nested reduction is a lot going on in only a few lines. I would definitely break the inner reduction off into its own function, give it a descriptive name, and call it in the outer reduction.



          (defn calc [size i prev] ; Although give it a better name
          (vec (reduce #(assoc %1 %2 false)
          prev
          (range (+ i i) size i))))

          (defn sieve [size]
          (-> (reduce (fn [prev i]
          (if (prev i)
          (calc size i prev)
          prev))
          (vec (repeat size true))
          (range 2 (-> size Math/sqrt int inc)))
          vec
          (assoc 0 false)
          (assoc 1 false)))


          I like breaking functions up. Having giant functions forces you to consider a large amount of data and interactions at once. If you split a part off into its own function and ensure that it's pure, you know that no code in that function can manipulate any data that you haven't explicitly given it as a parameter. That's one less bit of the code to need to look at when debugging.





          For your second bit, interestingly, it performed the same for me:



          (main) ; Using your arrays version
          "Elapsed time: 2106.530431 msecs"
          => 142913828922


          You're making a critical error though when dealing with arrays in Clojure: don't use aset unless you have to. aset works on Objects, not primitives, as its documentation notes:




          Sets the value at the index/indices. Works on Java arrays of
          reference types. Returns val.




          Using aset forces your bools to be boxed into a Boolean, which is pricey when done over and over. aset has multiple overloads for primitive types that should be used instead. I'd switch to aset-boolean, and create the array using boolean-array instead:



          (defn sieve2 [size]
          (-> (let [ar (boolean-array (repeat size true))]
          (dorun (map (fn [i]
          (when (aget ar i)
          (dorun (map (fn [j] (aset-boolean ar j false))
          (range (+ i i) size i)))))
          (range 2 (-> size Math/sqrt int inc))))
          ar)
          vec
          (assoc 0 false)
          (assoc 1 false)))

          (defn main
          (time
          (let [limit 2000000
          s (sieve2 limit)]
          (reduce #(+ %1 (if (s %2) %2 0))
          0 (range limit)))))

          (main)
          "Elapsed time: 759.412393 msecs"
          => 142913828922


          A little better. I'll also note though that use of (dorun (map is usually a code smell. You're better off just using mapv which is strict. Using laziness when you don't need it can be costly. maping isn't the right tool here for the job anyways. Use map when you want to transform a list. Use doseq when you want to carry out side effects over a list. Think of it as Java's enhanced for-loop. I'm also using doseq's :when clause to replace the use of the when macro:



          (defn sieve2 [size]
          (let [ar (boolean-array (repeat size true))]
          (doseq [i (range 2 (-> size (Math/sqrt) (int) (inc)))
          :when (aget ar i)] ; Replacing the call to when
          (doseq [j (range (+ i i) size i)]
          (aset-boolean ar j false)))

          (-> ar
          (vec)
          (assoc 0 false)
          (assoc 1 false))))

          (main)
          "Elapsed time: 577.607879 msecs"
          => 142913828922


          Still not great, but better.





          Just for a laugh comparison, here's a implementation of Eratosthenes' Sieve I wrote back in April:



          (defn sieve-primes [n]
          (loop [p 2 ; First prime
          marked #{} ; Found composites
          primes ]
          (let [mults (->> n
          (range p)
          (map #(* p %))
          (take-while #(< % n)))

          next-p (->> p
          (inc)
          (iterate inc)
          (remove marked)
          (first))

          new-primes (conj primes p)]

          (if (>= next-p n)
          new-primes
          (recur next-p (into marked mults) new-primes)))))

          (time
          (apply + (sieve-primes 2000000)))
          "Elapsed time: 8719.010487 msecs"
          => 142913828922


          Ouch! I don't think I tried very hard to get it lower though. That was the first time I had ever written the sieve in any language, and was happy with just having a working implementation at the time. It is pretty though, even if it's slow.





          Clojure is really not a performance-oriented language though. Yes, you can add all sorts of optimizations to make good use of all cores and limit intermediate lists when doing transformations, but it generally won't perform as well as other languages. It's generally even slower than Java of all languages in my experience. I write Clojure because it's fun to write and produces nice looking code, not because it produces fast code.






          share|improve this answer























          • I'm running on a budget Chromebook, which probably explains why my run time is even worse than your Surface Pro. But thanks for pointing me toward boolean-array and doseq. In addition to making it faster, I agree that the doseq forms definitely read better.
            – brian_o
            yesterday










          • Don't waste your time computing the sqrt at all. I'm not a Clojure expert, but surely there must be a way to express something like: while i * i < n. Which I have tested in other languages is more efficient than while i < sqrt(n).
            – Dair
            yesterday










          • @Dair Honestly, I had just come home from work when I wrote this. I was almost entirely concerned with just idiomatic Clojure. But yes, that would be (let [n (* size size)] (doseq [i (range 2 (inc (int n)). while could be used here, but it wouldn't be near as nice in the end and doseq.
            – Carcigenicate
            17 hours ago












          • @Carcigenicate Sorry if I sounded harsh. I wasn't thinking about it but "waste" is a bit of a strong word... It isn't that your answer is bad, I just see the sqrt thing used all the time, even in languages like C where performance does matter. I was more concerned with making sure the OP was aware of the alternative, but I had nothing to offer beyond that.
            – Dair
            10 hours ago








          • 1




            @Dair I’m not convinced computing sqrt is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit of sqrt.
            – AJNeufeld
            9 hours ago




















          up vote
          0
          down vote













          0.7 seconds for your Java implementation is too slow. We can speed that up (putting even more pressure on Closure):




          • Compute the sqrt once.

          • treat 2 as a special case

          • start at 3, start eliminations at $i^2$, and increment by 2i


          Eg)



          int limit = 1 + (int) Math.sqrt(size);
          for (int i = 3; i < limit); i += 2) {
          if (sieve[i]) {
          for (int j = i*i; j < size; j += 2*i) {
          sieve[j] = false;
          }
          }
          }

          long sum = 2;
          for (int i = 3; i < size; i += 2) {
          if (sieve[i]) sum += (long) i;
          }





          share|improve this answer























            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209094%2fproject-euler-10-sum-of-primes-less-than-two-million-in-clojure%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            1
            down vote













            I won't comment on the Java bit because I don't write Java very often. I agree with the other answer though that sqrt should only be called once. Computing the sqrt of a number is relatively expensive.





            First, for Clojure, a baseline on my computer:



            (defn sieve [size]
            (-> (reduce (fn [prev i]
            (if (prev i)
            (vec (reduce #(assoc %1 %2 false)
            prev
            (range (+ i i) size i)))
            prev))
            (vec (repeat size true))
            (range 2 (-> size Math/sqrt int inc)))
            vec
            (assoc 0 false)
            (assoc 1 false)))

            (defn main
            (time
            (let [limit 2000000
            s (sieve limit)]
            (reduce #(+ %1 (if (s %2) %2 0))
            0 (range limit)))))

            ; From REPL
            (main)
            "Elapsed time: 2274.584779 msecs"
            => 142913828922


            I should note that I'm on a crappy M3 Surface Pro 4; not a power machine by a stretch of any definition. If this is taking 14 seconds, you must have something else going on. That's far too long.





            I actually prefer wrapping threading calls in parenthesis, even if they aren't required. I'd write lines such as (-> size Math/sqrt int inc) as (-> size (Math/sqrt) (int) (inc)). I find it helps differentiating between the form being a plain function call, and the threading of a value. The only time I omit them is when I'm golfing.





            Your nested reduction is a lot going on in only a few lines. I would definitely break the inner reduction off into its own function, give it a descriptive name, and call it in the outer reduction.



            (defn calc [size i prev] ; Although give it a better name
            (vec (reduce #(assoc %1 %2 false)
            prev
            (range (+ i i) size i))))

            (defn sieve [size]
            (-> (reduce (fn [prev i]
            (if (prev i)
            (calc size i prev)
            prev))
            (vec (repeat size true))
            (range 2 (-> size Math/sqrt int inc)))
            vec
            (assoc 0 false)
            (assoc 1 false)))


            I like breaking functions up. Having giant functions forces you to consider a large amount of data and interactions at once. If you split a part off into its own function and ensure that it's pure, you know that no code in that function can manipulate any data that you haven't explicitly given it as a parameter. That's one less bit of the code to need to look at when debugging.





            For your second bit, interestingly, it performed the same for me:



            (main) ; Using your arrays version
            "Elapsed time: 2106.530431 msecs"
            => 142913828922


            You're making a critical error though when dealing with arrays in Clojure: don't use aset unless you have to. aset works on Objects, not primitives, as its documentation notes:




            Sets the value at the index/indices. Works on Java arrays of
            reference types. Returns val.




            Using aset forces your bools to be boxed into a Boolean, which is pricey when done over and over. aset has multiple overloads for primitive types that should be used instead. I'd switch to aset-boolean, and create the array using boolean-array instead:



            (defn sieve2 [size]
            (-> (let [ar (boolean-array (repeat size true))]
            (dorun (map (fn [i]
            (when (aget ar i)
            (dorun (map (fn [j] (aset-boolean ar j false))
            (range (+ i i) size i)))))
            (range 2 (-> size Math/sqrt int inc))))
            ar)
            vec
            (assoc 0 false)
            (assoc 1 false)))

            (defn main
            (time
            (let [limit 2000000
            s (sieve2 limit)]
            (reduce #(+ %1 (if (s %2) %2 0))
            0 (range limit)))))

            (main)
            "Elapsed time: 759.412393 msecs"
            => 142913828922


            A little better. I'll also note though that use of (dorun (map is usually a code smell. You're better off just using mapv which is strict. Using laziness when you don't need it can be costly. maping isn't the right tool here for the job anyways. Use map when you want to transform a list. Use doseq when you want to carry out side effects over a list. Think of it as Java's enhanced for-loop. I'm also using doseq's :when clause to replace the use of the when macro:



            (defn sieve2 [size]
            (let [ar (boolean-array (repeat size true))]
            (doseq [i (range 2 (-> size (Math/sqrt) (int) (inc)))
            :when (aget ar i)] ; Replacing the call to when
            (doseq [j (range (+ i i) size i)]
            (aset-boolean ar j false)))

            (-> ar
            (vec)
            (assoc 0 false)
            (assoc 1 false))))

            (main)
            "Elapsed time: 577.607879 msecs"
            => 142913828922


            Still not great, but better.





            Just for a laugh comparison, here's a implementation of Eratosthenes' Sieve I wrote back in April:



            (defn sieve-primes [n]
            (loop [p 2 ; First prime
            marked #{} ; Found composites
            primes ]
            (let [mults (->> n
            (range p)
            (map #(* p %))
            (take-while #(< % n)))

            next-p (->> p
            (inc)
            (iterate inc)
            (remove marked)
            (first))

            new-primes (conj primes p)]

            (if (>= next-p n)
            new-primes
            (recur next-p (into marked mults) new-primes)))))

            (time
            (apply + (sieve-primes 2000000)))
            "Elapsed time: 8719.010487 msecs"
            => 142913828922


            Ouch! I don't think I tried very hard to get it lower though. That was the first time I had ever written the sieve in any language, and was happy with just having a working implementation at the time. It is pretty though, even if it's slow.





            Clojure is really not a performance-oriented language though. Yes, you can add all sorts of optimizations to make good use of all cores and limit intermediate lists when doing transformations, but it generally won't perform as well as other languages. It's generally even slower than Java of all languages in my experience. I write Clojure because it's fun to write and produces nice looking code, not because it produces fast code.






            share|improve this answer























            • I'm running on a budget Chromebook, which probably explains why my run time is even worse than your Surface Pro. But thanks for pointing me toward boolean-array and doseq. In addition to making it faster, I agree that the doseq forms definitely read better.
              – brian_o
              yesterday










            • Don't waste your time computing the sqrt at all. I'm not a Clojure expert, but surely there must be a way to express something like: while i * i < n. Which I have tested in other languages is more efficient than while i < sqrt(n).
              – Dair
              yesterday










            • @Dair Honestly, I had just come home from work when I wrote this. I was almost entirely concerned with just idiomatic Clojure. But yes, that would be (let [n (* size size)] (doseq [i (range 2 (inc (int n)). while could be used here, but it wouldn't be near as nice in the end and doseq.
              – Carcigenicate
              17 hours ago












            • @Carcigenicate Sorry if I sounded harsh. I wasn't thinking about it but "waste" is a bit of a strong word... It isn't that your answer is bad, I just see the sqrt thing used all the time, even in languages like C where performance does matter. I was more concerned with making sure the OP was aware of the alternative, but I had nothing to offer beyond that.
              – Dair
              10 hours ago








            • 1




              @Dair I’m not convinced computing sqrt is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit of sqrt.
              – AJNeufeld
              9 hours ago

















            up vote
            1
            down vote













            I won't comment on the Java bit because I don't write Java very often. I agree with the other answer though that sqrt should only be called once. Computing the sqrt of a number is relatively expensive.





            First, for Clojure, a baseline on my computer:



            (defn sieve [size]
            (-> (reduce (fn [prev i]
            (if (prev i)
            (vec (reduce #(assoc %1 %2 false)
            prev
            (range (+ i i) size i)))
            prev))
            (vec (repeat size true))
            (range 2 (-> size Math/sqrt int inc)))
            vec
            (assoc 0 false)
            (assoc 1 false)))

            (defn main
            (time
            (let [limit 2000000
            s (sieve limit)]
            (reduce #(+ %1 (if (s %2) %2 0))
            0 (range limit)))))

            ; From REPL
            (main)
            "Elapsed time: 2274.584779 msecs"
            => 142913828922


            I should note that I'm on a crappy M3 Surface Pro 4; not a power machine by a stretch of any definition. If this is taking 14 seconds, you must have something else going on. That's far too long.





            I actually prefer wrapping threading calls in parenthesis, even if they aren't required. I'd write lines such as (-> size Math/sqrt int inc) as (-> size (Math/sqrt) (int) (inc)). I find it helps differentiating between the form being a plain function call, and the threading of a value. The only time I omit them is when I'm golfing.





            Your nested reduction is a lot going on in only a few lines. I would definitely break the inner reduction off into its own function, give it a descriptive name, and call it in the outer reduction.



            (defn calc [size i prev] ; Although give it a better name
            (vec (reduce #(assoc %1 %2 false)
            prev
            (range (+ i i) size i))))

            (defn sieve [size]
            (-> (reduce (fn [prev i]
            (if (prev i)
            (calc size i prev)
            prev))
            (vec (repeat size true))
            (range 2 (-> size Math/sqrt int inc)))
            vec
            (assoc 0 false)
            (assoc 1 false)))


            I like breaking functions up. Having giant functions forces you to consider a large amount of data and interactions at once. If you split a part off into its own function and ensure that it's pure, you know that no code in that function can manipulate any data that you haven't explicitly given it as a parameter. That's one less bit of the code to need to look at when debugging.





            For your second bit, interestingly, it performed the same for me:



            (main) ; Using your arrays version
            "Elapsed time: 2106.530431 msecs"
            => 142913828922


            You're making a critical error though when dealing with arrays in Clojure: don't use aset unless you have to. aset works on Objects, not primitives, as its documentation notes:




            Sets the value at the index/indices. Works on Java arrays of
            reference types. Returns val.




            Using aset forces your bools to be boxed into a Boolean, which is pricey when done over and over. aset has multiple overloads for primitive types that should be used instead. I'd switch to aset-boolean, and create the array using boolean-array instead:



            (defn sieve2 [size]
            (-> (let [ar (boolean-array (repeat size true))]
            (dorun (map (fn [i]
            (when (aget ar i)
            (dorun (map (fn [j] (aset-boolean ar j false))
            (range (+ i i) size i)))))
            (range 2 (-> size Math/sqrt int inc))))
            ar)
            vec
            (assoc 0 false)
            (assoc 1 false)))

            (defn main
            (time
            (let [limit 2000000
            s (sieve2 limit)]
            (reduce #(+ %1 (if (s %2) %2 0))
            0 (range limit)))))

            (main)
            "Elapsed time: 759.412393 msecs"
            => 142913828922


            A little better. I'll also note though that use of (dorun (map is usually a code smell. You're better off just using mapv which is strict. Using laziness when you don't need it can be costly. maping isn't the right tool here for the job anyways. Use map when you want to transform a list. Use doseq when you want to carry out side effects over a list. Think of it as Java's enhanced for-loop. I'm also using doseq's :when clause to replace the use of the when macro:



            (defn sieve2 [size]
            (let [ar (boolean-array (repeat size true))]
            (doseq [i (range 2 (-> size (Math/sqrt) (int) (inc)))
            :when (aget ar i)] ; Replacing the call to when
            (doseq [j (range (+ i i) size i)]
            (aset-boolean ar j false)))

            (-> ar
            (vec)
            (assoc 0 false)
            (assoc 1 false))))

            (main)
            "Elapsed time: 577.607879 msecs"
            => 142913828922


            Still not great, but better.





            Just for a laugh comparison, here's a implementation of Eratosthenes' Sieve I wrote back in April:



            (defn sieve-primes [n]
            (loop [p 2 ; First prime
            marked #{} ; Found composites
            primes ]
            (let [mults (->> n
            (range p)
            (map #(* p %))
            (take-while #(< % n)))

            next-p (->> p
            (inc)
            (iterate inc)
            (remove marked)
            (first))

            new-primes (conj primes p)]

            (if (>= next-p n)
            new-primes
            (recur next-p (into marked mults) new-primes)))))

            (time
            (apply + (sieve-primes 2000000)))
            "Elapsed time: 8719.010487 msecs"
            => 142913828922


            Ouch! I don't think I tried very hard to get it lower though. That was the first time I had ever written the sieve in any language, and was happy with just having a working implementation at the time. It is pretty though, even if it's slow.





            Clojure is really not a performance-oriented language though. Yes, you can add all sorts of optimizations to make good use of all cores and limit intermediate lists when doing transformations, but it generally won't perform as well as other languages. It's generally even slower than Java of all languages in my experience. I write Clojure because it's fun to write and produces nice looking code, not because it produces fast code.






            share|improve this answer























            • I'm running on a budget Chromebook, which probably explains why my run time is even worse than your Surface Pro. But thanks for pointing me toward boolean-array and doseq. In addition to making it faster, I agree that the doseq forms definitely read better.
              – brian_o
              yesterday










            • Don't waste your time computing the sqrt at all. I'm not a Clojure expert, but surely there must be a way to express something like: while i * i < n. Which I have tested in other languages is more efficient than while i < sqrt(n).
              – Dair
              yesterday










            • @Dair Honestly, I had just come home from work when I wrote this. I was almost entirely concerned with just idiomatic Clojure. But yes, that would be (let [n (* size size)] (doseq [i (range 2 (inc (int n)). while could be used here, but it wouldn't be near as nice in the end and doseq.
              – Carcigenicate
              17 hours ago












            • @Carcigenicate Sorry if I sounded harsh. I wasn't thinking about it but "waste" is a bit of a strong word... It isn't that your answer is bad, I just see the sqrt thing used all the time, even in languages like C where performance does matter. I was more concerned with making sure the OP was aware of the alternative, but I had nothing to offer beyond that.
              – Dair
              10 hours ago








            • 1




              @Dair I’m not convinced computing sqrt is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit of sqrt.
              – AJNeufeld
              9 hours ago















            up vote
            1
            down vote










            up vote
            1
            down vote









            I won't comment on the Java bit because I don't write Java very often. I agree with the other answer though that sqrt should only be called once. Computing the sqrt of a number is relatively expensive.





            First, for Clojure, a baseline on my computer:



            (defn sieve [size]
            (-> (reduce (fn [prev i]
            (if (prev i)
            (vec (reduce #(assoc %1 %2 false)
            prev
            (range (+ i i) size i)))
            prev))
            (vec (repeat size true))
            (range 2 (-> size Math/sqrt int inc)))
            vec
            (assoc 0 false)
            (assoc 1 false)))

            (defn main
            (time
            (let [limit 2000000
            s (sieve limit)]
            (reduce #(+ %1 (if (s %2) %2 0))
            0 (range limit)))))

            ; From REPL
            (main)
            "Elapsed time: 2274.584779 msecs"
            => 142913828922


            I should note that I'm on a crappy M3 Surface Pro 4; not a power machine by a stretch of any definition. If this is taking 14 seconds, you must have something else going on. That's far too long.





            I actually prefer wrapping threading calls in parenthesis, even if they aren't required. I'd write lines such as (-> size Math/sqrt int inc) as (-> size (Math/sqrt) (int) (inc)). I find it helps differentiating between the form being a plain function call, and the threading of a value. The only time I omit them is when I'm golfing.





            Your nested reduction is a lot going on in only a few lines. I would definitely break the inner reduction off into its own function, give it a descriptive name, and call it in the outer reduction.



            (defn calc [size i prev] ; Although give it a better name
            (vec (reduce #(assoc %1 %2 false)
            prev
            (range (+ i i) size i))))

            (defn sieve [size]
            (-> (reduce (fn [prev i]
            (if (prev i)
            (calc size i prev)
            prev))
            (vec (repeat size true))
            (range 2 (-> size Math/sqrt int inc)))
            vec
            (assoc 0 false)
            (assoc 1 false)))


            I like breaking functions up. Having giant functions forces you to consider a large amount of data and interactions at once. If you split a part off into its own function and ensure that it's pure, you know that no code in that function can manipulate any data that you haven't explicitly given it as a parameter. That's one less bit of the code to need to look at when debugging.





            For your second bit, interestingly, it performed the same for me:



            (main) ; Using your arrays version
            "Elapsed time: 2106.530431 msecs"
            => 142913828922


            You're making a critical error though when dealing with arrays in Clojure: don't use aset unless you have to. aset works on Objects, not primitives, as its documentation notes:




            Sets the value at the index/indices. Works on Java arrays of
            reference types. Returns val.




            Using aset forces your bools to be boxed into a Boolean, which is pricey when done over and over. aset has multiple overloads for primitive types that should be used instead. I'd switch to aset-boolean, and create the array using boolean-array instead:



            (defn sieve2 [size]
            (-> (let [ar (boolean-array (repeat size true))]
            (dorun (map (fn [i]
            (when (aget ar i)
            (dorun (map (fn [j] (aset-boolean ar j false))
            (range (+ i i) size i)))))
            (range 2 (-> size Math/sqrt int inc))))
            ar)
            vec
            (assoc 0 false)
            (assoc 1 false)))

            (defn main
            (time
            (let [limit 2000000
            s (sieve2 limit)]
            (reduce #(+ %1 (if (s %2) %2 0))
            0 (range limit)))))

            (main)
            "Elapsed time: 759.412393 msecs"
            => 142913828922


            A little better. I'll also note though that use of (dorun (map is usually a code smell. You're better off just using mapv which is strict. Using laziness when you don't need it can be costly. maping isn't the right tool here for the job anyways. Use map when you want to transform a list. Use doseq when you want to carry out side effects over a list. Think of it as Java's enhanced for-loop. I'm also using doseq's :when clause to replace the use of the when macro:



            (defn sieve2 [size]
            (let [ar (boolean-array (repeat size true))]
            (doseq [i (range 2 (-> size (Math/sqrt) (int) (inc)))
            :when (aget ar i)] ; Replacing the call to when
            (doseq [j (range (+ i i) size i)]
            (aset-boolean ar j false)))

            (-> ar
            (vec)
            (assoc 0 false)
            (assoc 1 false))))

            (main)
            "Elapsed time: 577.607879 msecs"
            => 142913828922


            Still not great, but better.





            Just for a laugh comparison, here's a implementation of Eratosthenes' Sieve I wrote back in April:



            (defn sieve-primes [n]
            (loop [p 2 ; First prime
            marked #{} ; Found composites
            primes ]
            (let [mults (->> n
            (range p)
            (map #(* p %))
            (take-while #(< % n)))

            next-p (->> p
            (inc)
            (iterate inc)
            (remove marked)
            (first))

            new-primes (conj primes p)]

            (if (>= next-p n)
            new-primes
            (recur next-p (into marked mults) new-primes)))))

            (time
            (apply + (sieve-primes 2000000)))
            "Elapsed time: 8719.010487 msecs"
            => 142913828922


            Ouch! I don't think I tried very hard to get it lower though. That was the first time I had ever written the sieve in any language, and was happy with just having a working implementation at the time. It is pretty though, even if it's slow.





            Clojure is really not a performance-oriented language though. Yes, you can add all sorts of optimizations to make good use of all cores and limit intermediate lists when doing transformations, but it generally won't perform as well as other languages. It's generally even slower than Java of all languages in my experience. I write Clojure because it's fun to write and produces nice looking code, not because it produces fast code.






            share|improve this answer














            I won't comment on the Java bit because I don't write Java very often. I agree with the other answer though that sqrt should only be called once. Computing the sqrt of a number is relatively expensive.





            First, for Clojure, a baseline on my computer:



            (defn sieve [size]
            (-> (reduce (fn [prev i]
            (if (prev i)
            (vec (reduce #(assoc %1 %2 false)
            prev
            (range (+ i i) size i)))
            prev))
            (vec (repeat size true))
            (range 2 (-> size Math/sqrt int inc)))
            vec
            (assoc 0 false)
            (assoc 1 false)))

            (defn main
            (time
            (let [limit 2000000
            s (sieve limit)]
            (reduce #(+ %1 (if (s %2) %2 0))
            0 (range limit)))))

            ; From REPL
            (main)
            "Elapsed time: 2274.584779 msecs"
            => 142913828922


            I should note that I'm on a crappy M3 Surface Pro 4; not a power machine by a stretch of any definition. If this is taking 14 seconds, you must have something else going on. That's far too long.





            I actually prefer wrapping threading calls in parenthesis, even if they aren't required. I'd write lines such as (-> size Math/sqrt int inc) as (-> size (Math/sqrt) (int) (inc)). I find it helps differentiating between the form being a plain function call, and the threading of a value. The only time I omit them is when I'm golfing.





            Your nested reduction is a lot going on in only a few lines. I would definitely break the inner reduction off into its own function, give it a descriptive name, and call it in the outer reduction.



            (defn calc [size i prev] ; Although give it a better name
            (vec (reduce #(assoc %1 %2 false)
            prev
            (range (+ i i) size i))))

            (defn sieve [size]
            (-> (reduce (fn [prev i]
            (if (prev i)
            (calc size i prev)
            prev))
            (vec (repeat size true))
            (range 2 (-> size Math/sqrt int inc)))
            vec
            (assoc 0 false)
            (assoc 1 false)))


            I like breaking functions up. Having giant functions forces you to consider a large amount of data and interactions at once. If you split a part off into its own function and ensure that it's pure, you know that no code in that function can manipulate any data that you haven't explicitly given it as a parameter. That's one less bit of the code to need to look at when debugging.





            For your second bit, interestingly, it performed the same for me:



            (main) ; Using your arrays version
            "Elapsed time: 2106.530431 msecs"
            => 142913828922


            You're making a critical error though when dealing with arrays in Clojure: don't use aset unless you have to. aset works on Objects, not primitives, as its documentation notes:




            Sets the value at the index/indices. Works on Java arrays of
            reference types. Returns val.




            Using aset forces your bools to be boxed into a Boolean, which is pricey when done over and over. aset has multiple overloads for primitive types that should be used instead. I'd switch to aset-boolean, and create the array using boolean-array instead:



            (defn sieve2 [size]
            (-> (let [ar (boolean-array (repeat size true))]
            (dorun (map (fn [i]
            (when (aget ar i)
            (dorun (map (fn [j] (aset-boolean ar j false))
            (range (+ i i) size i)))))
            (range 2 (-> size Math/sqrt int inc))))
            ar)
            vec
            (assoc 0 false)
            (assoc 1 false)))

            (defn main
            (time
            (let [limit 2000000
            s (sieve2 limit)]
            (reduce #(+ %1 (if (s %2) %2 0))
            0 (range limit)))))

            (main)
            "Elapsed time: 759.412393 msecs"
            => 142913828922


            A little better. I'll also note though that use of (dorun (map is usually a code smell. You're better off just using mapv which is strict. Using laziness when you don't need it can be costly. maping isn't the right tool here for the job anyways. Use map when you want to transform a list. Use doseq when you want to carry out side effects over a list. Think of it as Java's enhanced for-loop. I'm also using doseq's :when clause to replace the use of the when macro:



            (defn sieve2 [size]
            (let [ar (boolean-array (repeat size true))]
            (doseq [i (range 2 (-> size (Math/sqrt) (int) (inc)))
            :when (aget ar i)] ; Replacing the call to when
            (doseq [j (range (+ i i) size i)]
            (aset-boolean ar j false)))

            (-> ar
            (vec)
            (assoc 0 false)
            (assoc 1 false))))

            (main)
            "Elapsed time: 577.607879 msecs"
            => 142913828922


            Still not great, but better.





            Just for a laugh comparison, here's a implementation of Eratosthenes' Sieve I wrote back in April:



            (defn sieve-primes [n]
            (loop [p 2 ; First prime
            marked #{} ; Found composites
            primes ]
            (let [mults (->> n
            (range p)
            (map #(* p %))
            (take-while #(< % n)))

            next-p (->> p
            (inc)
            (iterate inc)
            (remove marked)
            (first))

            new-primes (conj primes p)]

            (if (>= next-p n)
            new-primes
            (recur next-p (into marked mults) new-primes)))))

            (time
            (apply + (sieve-primes 2000000)))
            "Elapsed time: 8719.010487 msecs"
            => 142913828922


            Ouch! I don't think I tried very hard to get it lower though. That was the first time I had ever written the sieve in any language, and was happy with just having a working implementation at the time. It is pretty though, even if it's slow.





            Clojure is really not a performance-oriented language though. Yes, you can add all sorts of optimizations to make good use of all cores and limit intermediate lists when doing transformations, but it generally won't perform as well as other languages. It's generally even slower than Java of all languages in my experience. I write Clojure because it's fun to write and produces nice looking code, not because it produces fast code.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 3 hours ago

























            answered yesterday









            Carcigenicate

            2,58811229




            2,58811229












            • I'm running on a budget Chromebook, which probably explains why my run time is even worse than your Surface Pro. But thanks for pointing me toward boolean-array and doseq. In addition to making it faster, I agree that the doseq forms definitely read better.
              – brian_o
              yesterday










            • Don't waste your time computing the sqrt at all. I'm not a Clojure expert, but surely there must be a way to express something like: while i * i < n. Which I have tested in other languages is more efficient than while i < sqrt(n).
              – Dair
              yesterday










            • @Dair Honestly, I had just come home from work when I wrote this. I was almost entirely concerned with just idiomatic Clojure. But yes, that would be (let [n (* size size)] (doseq [i (range 2 (inc (int n)). while could be used here, but it wouldn't be near as nice in the end and doseq.
              – Carcigenicate
              17 hours ago












            • @Carcigenicate Sorry if I sounded harsh. I wasn't thinking about it but "waste" is a bit of a strong word... It isn't that your answer is bad, I just see the sqrt thing used all the time, even in languages like C where performance does matter. I was more concerned with making sure the OP was aware of the alternative, but I had nothing to offer beyond that.
              – Dair
              10 hours ago








            • 1




              @Dair I’m not convinced computing sqrt is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit of sqrt.
              – AJNeufeld
              9 hours ago




















            • I'm running on a budget Chromebook, which probably explains why my run time is even worse than your Surface Pro. But thanks for pointing me toward boolean-array and doseq. In addition to making it faster, I agree that the doseq forms definitely read better.
              – brian_o
              yesterday










            • Don't waste your time computing the sqrt at all. I'm not a Clojure expert, but surely there must be a way to express something like: while i * i < n. Which I have tested in other languages is more efficient than while i < sqrt(n).
              – Dair
              yesterday










            • @Dair Honestly, I had just come home from work when I wrote this. I was almost entirely concerned with just idiomatic Clojure. But yes, that would be (let [n (* size size)] (doseq [i (range 2 (inc (int n)). while could be used here, but it wouldn't be near as nice in the end and doseq.
              – Carcigenicate
              17 hours ago












            • @Carcigenicate Sorry if I sounded harsh. I wasn't thinking about it but "waste" is a bit of a strong word... It isn't that your answer is bad, I just see the sqrt thing used all the time, even in languages like C where performance does matter. I was more concerned with making sure the OP was aware of the alternative, but I had nothing to offer beyond that.
              – Dair
              10 hours ago








            • 1




              @Dair I’m not convinced computing sqrt is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit of sqrt.
              – AJNeufeld
              9 hours ago


















            I'm running on a budget Chromebook, which probably explains why my run time is even worse than your Surface Pro. But thanks for pointing me toward boolean-array and doseq. In addition to making it faster, I agree that the doseq forms definitely read better.
            – brian_o
            yesterday




            I'm running on a budget Chromebook, which probably explains why my run time is even worse than your Surface Pro. But thanks for pointing me toward boolean-array and doseq. In addition to making it faster, I agree that the doseq forms definitely read better.
            – brian_o
            yesterday












            Don't waste your time computing the sqrt at all. I'm not a Clojure expert, but surely there must be a way to express something like: while i * i < n. Which I have tested in other languages is more efficient than while i < sqrt(n).
            – Dair
            yesterday




            Don't waste your time computing the sqrt at all. I'm not a Clojure expert, but surely there must be a way to express something like: while i * i < n. Which I have tested in other languages is more efficient than while i < sqrt(n).
            – Dair
            yesterday












            @Dair Honestly, I had just come home from work when I wrote this. I was almost entirely concerned with just idiomatic Clojure. But yes, that would be (let [n (* size size)] (doseq [i (range 2 (inc (int n)). while could be used here, but it wouldn't be near as nice in the end and doseq.
            – Carcigenicate
            17 hours ago






            @Dair Honestly, I had just come home from work when I wrote this. I was almost entirely concerned with just idiomatic Clojure. But yes, that would be (let [n (* size size)] (doseq [i (range 2 (inc (int n)). while could be used here, but it wouldn't be near as nice in the end and doseq.
            – Carcigenicate
            17 hours ago














            @Carcigenicate Sorry if I sounded harsh. I wasn't thinking about it but "waste" is a bit of a strong word... It isn't that your answer is bad, I just see the sqrt thing used all the time, even in languages like C where performance does matter. I was more concerned with making sure the OP was aware of the alternative, but I had nothing to offer beyond that.
            – Dair
            10 hours ago






            @Carcigenicate Sorry if I sounded harsh. I wasn't thinking about it but "waste" is a bit of a strong word... It isn't that your answer is bad, I just see the sqrt thing used all the time, even in languages like C where performance does matter. I was more concerned with making sure the OP was aware of the alternative, but I had nothing to offer beyond that.
            – Dair
            10 hours ago






            1




            1




            @Dair I’m not convinced computing sqrt is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit of sqrt.
            – AJNeufeld
            9 hours ago






            @Dair I’m not convinced computing sqrt is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit of sqrt.
            – AJNeufeld
            9 hours ago














            up vote
            0
            down vote













            0.7 seconds for your Java implementation is too slow. We can speed that up (putting even more pressure on Closure):




            • Compute the sqrt once.

            • treat 2 as a special case

            • start at 3, start eliminations at $i^2$, and increment by 2i


            Eg)



            int limit = 1 + (int) Math.sqrt(size);
            for (int i = 3; i < limit); i += 2) {
            if (sieve[i]) {
            for (int j = i*i; j < size; j += 2*i) {
            sieve[j] = false;
            }
            }
            }

            long sum = 2;
            for (int i = 3; i < size; i += 2) {
            if (sieve[i]) sum += (long) i;
            }





            share|improve this answer



























              up vote
              0
              down vote













              0.7 seconds for your Java implementation is too slow. We can speed that up (putting even more pressure on Closure):




              • Compute the sqrt once.

              • treat 2 as a special case

              • start at 3, start eliminations at $i^2$, and increment by 2i


              Eg)



              int limit = 1 + (int) Math.sqrt(size);
              for (int i = 3; i < limit); i += 2) {
              if (sieve[i]) {
              for (int j = i*i; j < size; j += 2*i) {
              sieve[j] = false;
              }
              }
              }

              long sum = 2;
              for (int i = 3; i < size; i += 2) {
              if (sieve[i]) sum += (long) i;
              }





              share|improve this answer

























                up vote
                0
                down vote










                up vote
                0
                down vote









                0.7 seconds for your Java implementation is too slow. We can speed that up (putting even more pressure on Closure):




                • Compute the sqrt once.

                • treat 2 as a special case

                • start at 3, start eliminations at $i^2$, and increment by 2i


                Eg)



                int limit = 1 + (int) Math.sqrt(size);
                for (int i = 3; i < limit); i += 2) {
                if (sieve[i]) {
                for (int j = i*i; j < size; j += 2*i) {
                sieve[j] = false;
                }
                }
                }

                long sum = 2;
                for (int i = 3; i < size; i += 2) {
                if (sieve[i]) sum += (long) i;
                }





                share|improve this answer














                0.7 seconds for your Java implementation is too slow. We can speed that up (putting even more pressure on Closure):




                • Compute the sqrt once.

                • treat 2 as a special case

                • start at 3, start eliminations at $i^2$, and increment by 2i


                Eg)



                int limit = 1 + (int) Math.sqrt(size);
                for (int i = 3; i < limit); i += 2) {
                if (sieve[i]) {
                for (int j = i*i; j < size; j += 2*i) {
                sieve[j] = false;
                }
                }
                }

                long sum = 2;
                for (int i = 3; i < size; i += 2) {
                if (sieve[i]) sum += (long) i;
                }






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited yesterday

























                answered yesterday









                AJNeufeld

                3,814317




                3,814317






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209094%2fproject-euler-10-sum-of-primes-less-than-two-million-in-clojure%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Morgemoulin

                    Scott Moir

                    Souastre