>
> 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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to