>
> You *really* shouldn't do nested defns. They're misleading, as defns
> *always* cause a global change.
> Just use separate functions.
>
Agreed, creating global functions that are meant to be local is no
good. Using letfn instead.
> > (. (. (* (+ a1 b1) (+ a1 b1))
> > divide (* t1 4M) digits round-mode)
> > setScale places round-mode)
>
> This is why I dislike . -- it's almost impossible to tell what
> operation you're applying, and to which operands because the operation
> name is not at the head of the list. :/
> If you really need to use the .divide methods directly, maybe you
> could use the -> macro like this:
>
> (-> (* (+ a1 b1) (+ a1 b1)) ; would be faster to (let [tmp (+ a1
> b1)] ...) first though.
> (.divide (* t1 4M) digits round-mode)
> (.setScale places round-mode)
Yes, it looks a little cleaner.
>
> Though I think setting the math context would be a better solution.
> eg.
> (binding
> [*math-context* (java.math.MathContext. 5 java.math.RoundingMode/
> HALF_UP)]
> (* 5M 1.1111105M))
> gives 5.5556M
This is interesting. Trying that and replacing .divide with / instead
results in a 10x slowdown.
$ time ~/src/clojure/clj pi.clj 10000 --> 112.685s
Otherwise, here's the cleaned up version :
(import 'java.lang.Math)
(import 'java.math.MathContext)
(import 'java.math.BigDecimal)
(defn sb-pi [places]
"Calculates PI digits using the Salamin-Brent algorithm
and Java's BigDecimal class."
(let [digits (+ 10 places) ;; add some guard digits
round-mode BigDecimal/ROUND_DOWN]
(letfn [(big-sqrt[#^BigDecimal num]
"Calculates square root using Newton's method."
(letfn [(big-sqrt-int
[#^BigDecimal num
#^BigDecimal x0
#^BigDecimal x1]
(let [x0new x1
x1new (-> num (.divide x0new digits round-
mode))
x1tot (-> (+ x1new x0new)
(.divide 2M digits round-mode))]
(if (= x0 x1)
x1tot
(recur num x1 x1tot))))]
(big-sqrt-int
num 0M (BigDecimal/valueOf
(Math/sqrt (. num doubleValue))))))
(sb-pi-int
[#^BigDecimal a #^BigDecimal b #^BigDecimal
t #^BigDecimal x #^BigDecimal y]
(let
[#^BigDecimal y1 a
#^BigDecimal a1 (-> (+ a b)
(.divide 2M digits round-mode))
#^BigDecimal b1 (big-sqrt (* b y1))
#^BigDecimal t1 (- t
(* x
(* (- y1 a1)
(- y1 a1))))
#^BigDecimal x1 (* x 2M)]
(if (-> a (.equals b))
(-> (* (+ a1 b1) (+ a1 b1))
(.divide (* t1 4M) digits round-mode)
(.setScale places round-mode))
(recur a1 b1 t1 x1 y1))))]
(sb-pi-int 1M
(-> 1M (.divide (big-sqrt 2M) digits round-mode))
(/ 1M 4M)
1M
nil))))
$ time ~/src/clojure/clj pi.clj 10000 --> 11.930s
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---