SBCL to newLISP

Started by kanen, June 28, 2010, 08:46:00 PM

Previous topic - Next topic

kanen

Can someone help me translate the following SBCL (or Common Lisp) script to newLISP?



I'm presenting at a conference and interested in showing benchmarks between a bunch of different languages (including some Lisp, Scheme, Python, C, etc).
; sbcl lisp version by mandeep singh

(declaim (optimize (speed 3)))

(defconstant +BAILOUT+ 16)
(defconstant +MAX-ITERATIONS+ 1000)

(defun mandelbrot (x y)
  (declare (type single-float x y))
  (let ((cr (- y 0.5))
        (ci x)
        (zi 0.0)
        (zr 0.0))
    (declare (type single-float cr ci zi zr))
    (do ((i 0 (incf i)))
        (nil)
      (let* ((temp (the single-float (* zr zi)))
             (zr2 (the single-float (* zr zr)))
             (zi2 (the single-float (* zi zi))))
        (declare (type single-float temp zr2 zi2)
                 (type fixnum i))
        (setq zr (the single-float (+ (- zr2 zi2) cr)))
        (setq zi (the single-float (+ temp temp ci)))
        (if (> (the single-float (+ zi2 zr2)) +BAILOUT+)
            (return-from mandelbrot i))
        (if (> i +MAX-ITERATIONS+)
            (return-from mandelbrot 0))))))
(defun main ()
   (let ((tstart)
   (tfinish))
     (setq tstart (get-internal-real-time))
     (do ((y -39 (incf y)))
    ((= (the fixnum y) 39))
       (format t "~%")
       (do ((x -39 (incf x)))
      ((= (the fixnum x) 39))
    (let ((i (mandelbrot (the single-float (/ x 40.0))
               (the single-float (/ y 40.0)))))
      (declare (type fixnum i x y))
        (if (zerop i)
            (format t "*")
            (format t " ")))))
     (format t "~%")
     (setq tfinish (get-internal-real-time))
     (format t "SBCL Elapsed ~,2F~%"
      (coerce (/ (- tfinish tstart) internal-time-units-per-second) 'float))))

(progn
 (main)
 (quit))
. Kanen Flowers http://kanen.me[/url] .

wandernet

#1

;newLISP v.10.0.0
;on Win32 IPv4 UTF-8
(import "kernel32.dll" "GetTickCount")
(set 'BAILOUT 16)
(set 'MAX_ITERATIONS 1000)

(define (iterate x y)
  (let ((cr (sub y 0.5))
   (ci x)
   (zi 0.0)
   (zr 0.0)
   (i 0))
(while 1
 (inc i 1)
 (set 'temp (mul zr zi))
 (set 'zr2 (mul zr zr))
 (set 'zi2 (mul zi zi))
 (set 'zr  (add cr (sub zr2 zi2)))
 (set 'zi  (add temp temp ci))
 (if (> (add zi2 zr2) BAILOUT)
        (throw i))
 (if (> i MAX_ITERATIONS)
   (throw 0)))))

(define (mandelbrot)
    (let ((t (GetTickCount)))
 (for (y -39 38)
(for (x -39 38)
(set 'j (catch (iterate (div x 40.0) (div y 40.0))))
            (if (= j 0.0)
 (print "*")
 (print " ")))
(print "n"))
 (println "Time Elapsed: " (- (GetTickCount) t))))

(mandelbrot)


Lutz

#2
faster: http://www.newlisp.org/mandelbrot.cgi">http://www.newlisp.org/mandelbrot.cgi



benchmarks: http://www.newlisp.org/benchmarks/">http://www.newlisp.org/benchmarks/

kanen

#3
I do not use Windows.



When I look at "GetTickCount" the reference reads, "Retrieves the number of milliseconds that have elapsed since the system was started, up to 49.7 days."



Seems like a simple (date-value) in newLISP can do the same thing, with a few modifications?



New code:
Quote;(import "kernel32.dll" "GetTickCount")

(define (GetTickCount)

   (date-value)

)


The problem (as Lutz says later) is that this code is SLOW compared to the same code in other languages. In fact, this example in newLISP is even slower than Python, which is impressive. :)


Quote from: "wandernet"
;newLISP v.10.0.0
;on Win32 IPv4 UTF-8
(import "kernel32.dll" "GetTickCount")
. Kanen Flowers http://kanen.me[/url] .

Lutz

#4
(date-value) gives only seconds of resolution, better use (time-of-day), which has at least milliseconds resolution and on modern Unix systems micro seconds of resolution.

cormullion

#5
Perhaps the Python uses built-in complex numbers...



I thought Michael's complex version was more fun:


(define (complex:complex
            (r 0)
            (i 0))
    (list complex r i))

(define (complex:rad)
    (set 're (self 1) 'im (self 2))
    (sqrt (add
            (mul re re)
            (mul im im))))

(define (complex:theta)
    (atan (div
            (self 1)
            (self 2))))

(define (complex:add b)
    (complex (add
                (self 1)
                (b 1))
             (add
                (self 2)
                (b 2))))

(define (complex:mul  b)
    (set 'a.re (self 1)
         'a.im (self 2)
         'b.re (b 1)
         'b.im (b 2))
    (complex
         (sub
            (mul a.re b.re)
            (mul a.im b.im))
         (add
            (mul a.re b.im)
            (mul a.im b.re))))

(define (mandelbrot)
    (for (y -2 2 0.02)
        (for (x -2 2 0.02)
            (inc counter)
            (set 'z (complex x y) 'c 126 'a z)
            (while (and
                    (< (abs (:rad (set 'z (:add (:mul z z) a)))) 2)
                    (> (dec c) 32)))
            (print (char c)))
        (println)))

(mandelbrot)

Tim Johnson

#6
Also, why use multiple calls to 'set when one will do?

cheers

tim
Programmer since 1987. Unix environment.

m i c h a e l

#7
And a single call to set is faster, too:


(define (test-once) (set 'a 1 'b 2 'c 3 'd 4 'e 5 'f 6 'g 7))

(define (test-multiple)
(set 'a 1)
(set 'b 2)
(set 'c 3)
(set 'd 4)
(set 'e 5)
(set 'f 6)
(set 'g 7)
)

(time (test-once) 1000000) ;=> 447.211
(time (test-multiple) 1000000) ;=> 609.038


m i c h a e l

Tim Johnson

#8
I'll buy that one. I wonder if differences would change with more complex data types?

thanks

tim
Programmer since 1987. Unix environment.

itistoday

#9
Regarding the set thing... I've actually done the same benchmarks, and they've affected how I decide to use set or setf.



Basically, I've found that setf is faster for situations where only 1 variable needs to be set, but if you're setting multiple things in a row, set is faster (if called once for all of them).



It's a really insignificant difference on its own, but I figure if I make that a convention the times will eventually add up to something meaningful since set is called so much. newlisp makes it easy to microbenchmark, and so you can adjust your coding style to always use the faster version, and eventually I figure the entire program benefits from the lots-of-minor-performance-increases.
Get your Objective newLISP groove on.

Tim Johnson

#10
The idea of using one call to set

with multiple symbol/value pairs

versus

multiple calls to set

with just one symbol/value pair for each call

appeals to my aversion to redundancy.

but michael makes a compelling case in the test code that he posted.



I should have some time in the next few days to run some more complex tests where

the variables are something other than integers.



thanks

tim
Programmer since 1987. Unix environment.

itistoday

#11
Quote from: "Tim Johnson"The idea of using one call to set

with multiple symbol/value pairs

versus

multiple calls to set

with just one symbol/value pair for each call

appeals to my aversion to redundancy.

but michael makes a compelling case in the test code that he posted.


I don't understand, why "but"? His test code shows it's better to use one call.
Get your Objective newLISP groove on.

Tim Johnson

#12
Quote
I don't understand, why "but"? His test code shows it's better to use one call.

Oh for Pete's Sake, you're right, my brain has been AWOL these couple of days!

I misread the results.

thanks

tim
Programmer since 1987. Unix environment.

m i c h a e l

#13
setf is faster than set:


(define (test-setf-once) (setf a 1 b 2 c 3 d 4 e 5 f 6 g 7))

(define (test-setf-multiple)
(setf a 1)
(setf b 2)
(setf c 3)
(setf d 4)
(setf e 5)
(setf f 6)
(setf g 7)
)


(println (time (test-setf-once) 1000000)) ;=> 372.934
(println (time (test-setf-multiple) 1000000)) ;=> 507.426


Curious.



m i c h a e l

Tim Johnson

#14
Michael, I've never used setf like that. The docs say
Quotesetf is used when setting list or array references

but I see from my own console:

> (setf a 1)
1
> a
1

Curiouser and curiouser
Programmer since 1987. Unix environment.