Obviously there are better ways of obtaining Pi, but for educational purposes, how is the code below?
(defn leibniz-numerator [x] (* (- (rem x 4) 2) -4.0))
(defn calc-pi-leibniz
"Calculate pi with Leibniz formula
4/1 - 4/3 + 4/5 - 4/7 + 4/9 etc
Very slow convergence"
[terms]
(reduce + (map #(/ (leibniz-numerator %) %) (range 1 terms 2))))
(print (calc-pi-leibniz 10000000))
1 Answer 1
I'd say your solution is pretty good! Since you probably won't re-use your leibniz-numerator
function, you might want to make it private by declaring it with defn-
, or you could declare it within the body of your main function using let
or letfn
.
Also, you might notice that your function actually computes pi with half the number of terms given has parameters (might not be of importance).
I can share some alternatives I came up with.
We could start by generating the sequence (4 -4 4 -4...)
. To do that, we can use the method iterate
:
(take 4 (iterate - 4))
;;=> (4 -4 4 -4)
Then we want the sequence (1 3 5 7)
. You already found method range
for that:
(take 4 (range 1 10 2))
;;=> (1 3 5 7)
If you divide those to element wise, you will get (4 -4/3 4/5 -4/7...)
. You can do that with map
(take 4 (map / (iterate - 4) (range 1 10 2)))
;;=> (4 -4/3 4/5 -4/7)
In our final computation, this can get really slow because we're using decimals. Let's use floats instead, and put everything together:
(defn calc-pi-leibniz [terms]
(reduce + (map / (iterate - 4.0) (range 1.0 terms 2.0))))
But for some reason, this is 5 times slower than your solution. If someone could tell me why, I'd be grateful. I suspect that is because map has to go through two lists instead of one, but since they are both lazy this should not matter?
For a faster solution (but less elegant), we can see that there are two subsequences in the leibniz formula. One that is (4 4/5 4/9)
and one that is (-4/3 -4/7 -4/11)
. With that in mind, you can get the following:
(defn calc-pi-leibniz [terms]
(* 4 (- (reduce + (map / (range 1.0 terms 4.0)))
(reduce + (map / (range 3.0 terms 4.0))))))
Which runs as fast as your solution.