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