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?
performance programming-challenge comparative-review clojure sieve-of-eratosthenes
add a comment |
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?
performance programming-challenge comparative-review clojure sieve-of-eratosthenes
add a comment |
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?
performance programming-challenge comparative-review clojure sieve-of-eratosthenes
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
performance programming-challenge comparative-review clojure sieve-of-eratosthenes
edited yesterday
200_success
127k15149412
127k15149412
asked yesterday
brian_o
77949
77949
add a comment |
add a comment |
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 Object
s, 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. map
ing 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.
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 towardboolean-array
anddoseq
. In addition to making it faster, I agree that thedoseq
forms definitely read better.
– brian_o
yesterday
Don't waste your time computing thesqrt
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 thanwhile 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 anddoseq
.
– 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 thesqrt
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 computingsqrt
is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit ofsqrt
.
– AJNeufeld
9 hours ago
|
show 1 more comment
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;
}
add a comment |
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 Object
s, 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. map
ing 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.
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 towardboolean-array
anddoseq
. In addition to making it faster, I agree that thedoseq
forms definitely read better.
– brian_o
yesterday
Don't waste your time computing thesqrt
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 thanwhile 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 anddoseq
.
– 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 thesqrt
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 computingsqrt
is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit ofsqrt
.
– AJNeufeld
9 hours ago
|
show 1 more comment
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 Object
s, 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. map
ing 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.
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 towardboolean-array
anddoseq
. In addition to making it faster, I agree that thedoseq
forms definitely read better.
– brian_o
yesterday
Don't waste your time computing thesqrt
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 thanwhile 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 anddoseq
.
– 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 thesqrt
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 computingsqrt
is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit ofsqrt
.
– AJNeufeld
9 hours ago
|
show 1 more comment
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 Object
s, 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. map
ing 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.
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 Object
s, 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. map
ing 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.
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 towardboolean-array
anddoseq
. In addition to making it faster, I agree that thedoseq
forms definitely read better.
– brian_o
yesterday
Don't waste your time computing thesqrt
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 thanwhile 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 anddoseq
.
– 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 thesqrt
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 computingsqrt
is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit ofsqrt
.
– AJNeufeld
9 hours ago
|
show 1 more comment
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 towardboolean-array
anddoseq
. In addition to making it faster, I agree that thedoseq
forms definitely read better.
– brian_o
yesterday
Don't waste your time computing thesqrt
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 thanwhile 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 anddoseq
.
– 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 thesqrt
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 computingsqrt
is a waste. It can be done once, instead of doing 1000000 i*i calculations. The larger n becomes, the larger the benefit ofsqrt
.
– 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
|
show 1 more comment
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;
}
add a comment |
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;
}
add a comment |
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;
}
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;
}
edited yesterday
answered yesterday
AJNeufeld
3,814317
3,814317
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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