Thanks a lot, that's really helpful. I never thought of using a macro to define constants like that, it's definitely a good trick and it does seem to result in the biggest performance gain.
On Apr 2, 7:25 am, Paul Stadig <p...@stadig.name> wrote: > I got it down to about 3 seconds. I did what William said, but the biggest > improvement was from changing the way *width*, *height*, and *max-steps* > were defined. I noticed that in the Java version they are constants, but in > the Clojure version they are Vars which means that inside your tight inner > loops you are dereferencing the vars multiple times. Vars are for thread > local values, but these values are not expected to change. I'm not sure the > best way to make these vars into constants, but I changed them into macros: > > (defmacro *width* [] (float 640)) > > Then replaced instances of *width* with (*width*). The macros will get > compiled down to floats instead of resulting in multiple Var.deref calls > (and probably Number.floatValue calls) per loop iteration. > > Here is the code: > > (ns main > (:import (java.awt Color Container Graphics Canvas Dimension) > (javax.swing JPanel JFrame) > (java.awt.image BufferedImage BufferStrategy))) > > (set! *warn-on-reflection* true) > > (defmacro *width* [] (float 640)) > (defmacro *height* [] (float 640)) > (defmacro *max-steps* [] (float 32)) > > (defn on-thread [#^Runnable f] (doto (new Thread f) (.start))) > > (defn check-bounds [x y] > (loop [px (float x) > py (float y) > zx (float 0.0) > zy (float 0.0) > zx2 (float 0.0) > zy2 (float 0.0) > value (float 0)] > (if (and (< value (*max-steps*)) (< (+ zx2 zy2) (float 4.0))) > (let [new-zy (float (+ (* (float 2.0) zx zy) py)) > new-zx (float (+ (- zx2 zy2) px)) > new-zx2 (float (* new-zx new-zx)) > new-zy2 (float (* new-zy new-zy))] > (recur px py new-zx new-zy new-zx2 new-zy2 (inc value))) > (if (== value (*max-steps*)) 0 value)))) > > (defn draw-line [#^Graphics g y] > (let [dy (- 1.25 (* 2.5 (/ y (*height*))))] > (doseq [x (range 0 (*width*))] > (let [dx (- (* 2.5 (/ x (*width*))) 2.0)] > (let [value (check-bounds dx dy)] > (if (> value 0) > (doto g > (. setColor (Color. (* value (/ 255 > (*max-steps*))))) > (. drawRect x y 0 0)))))))) > > (defn draw-lines > ([buffer g] (draw-lines buffer g (*height*))) > ([#^BufferStrategy buffer g y] > (doseq [y (range 0 y)] > (draw-line g y) > ;(on-thread (draw-line g y)) > (. buffer show)))) > > (defn draw [#^Canvas canvas] > (let [buffer (. canvas getBufferStrategy) > g (. buffer getDrawGraphics)] > (draw-lines buffer g))) > > (defn main [] > > (let [panel (JPanel.) > canvas (Canvas.) > frame (JFrame. "Mandelbrot")] > > (doto panel > (.setPreferredSize (Dimension. (*width*) (*height*))) > (.setLayout nil) > (.add canvas)) > > (doto frame > (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE) > (.setBounds 0,0,(*width*) (*height*)) > (.setResizable false) > (.add panel) > (.setVisible true)) > > (doto canvas > (.setBounds 0,0,(*width*) (*height*)) > (.setBackground (Color/BLACK)) > (.createBufferStrategy 2) > (.requestFocus)) > > (draw canvas))) > > (time (main)) > > ~$ clojure /tmp/mandelbrot.clj > "Elapsed time: 3577.128587 msecs" > > Paul --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---