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

Reply via email to