Took a shot at implementing PI in Clojure using a reasonably fast
algorithm.
So why is it so slow ? Is BigDecimal just that bad ? Would fixed point
arithmetic be better using BigInteger ?
(MacBook Pro - Intel Core 2 Duo 2.26 GHz - 4GB RAM)


(set! *warn-on-reflection* true)

(import 'java.lang.Math)
(import 'java.math.MathContext)
(import 'java.math.RoundingMode)
(import 'java.math.BigInteger)
(import 'java.math.BigDecimal)


(defn sb-pi [digits]
  "Calculates PI digits using the Salamin-Brent algorithm
   and Java's BigDecimal class."

  (let [mcdigits (new MathContext (+ 10 digits)) ; add 10 guard digits
        zero (new BigDecimal 0)
        one (new BigDecimal 1)
        two (new BigDecimal 2)
        four (new BigDecimal 4)]

    (defn big-sqrt[#^BigDecimal num digits]
      "Calculates square root using Newton's method."

      (defn big-sqrt-int
        [#^BigDecimal num
         #^BigDecimal x0
         #^BigDecimal x1
         digits]
        (if (not (. x0 equals x1))
          (big-sqrt-int
           num x1
           (. (. x1 add (. num divide x1 digits RoundingMode/
HALF_DOWN))
              divide two digits RoundingMode/HALF_DOWN)
           digits)
          x1))
      (big-sqrt-int
       num zero (. BigDecimal valueOf (Math/sqrt (. num doubleValue)))
(+ 1 digits)))

    (defn sb-pi-int
      [#^BigDecimal a #^BigDecimal b #^BigDecimal x #^BigDecimal p n]

      (let
          [#^BigDecimal a1 (. (. a add b) divide two mcdigits)
           #^BigDecimal b1 (big-sqrt (. a multiply b mcdigits) digits)
           #^BigDecimal x1 (. x subtract
                              (. p multiply
                                 (. (. a subtract a1) multiply (. a
subtract a1)
                                    mcdigits) mcdigits))
           #^BigDecimal p1 (. two multiply p mcdigits)]
        (if (> n digits)
          (. (. (. (. a1 add b1) multiply (. a1 add b1) mcdigits)
                divide (. four multiply x1) mcdigits) setScale digits
RoundingMode/HALF_UP)
          (recur a1 b1 x1 p1 (* 2 n)))))

    (let
        [#^BigDecimal sa one
         #^BigDecimal sb (. one divide (big-sqrt two digits) mcdigits)
         #^BigDecimal sx (. one divide four)
         #^BigDecimal sp one]
      (sb-pi-int sa sb sx sp 1)
      )))

(time (println (sb-pi 1)))       ;; 4.058 ms
(time (println (sb-pi 10)))      ;; 6.611 ms
(time (println (sb-pi 100)))     ;; 21.615 ms
(time (println (sb-pi 1000)))    ;; 211.314 ms
(time (println (sb-pi 10000)))   ;; 22090.236 ms


--~--~---------~--~----~------------~-------~--~----~
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