Page 1 of 1
SBCL to newLISP
Posted: Tue Jun 29, 2010 3:46 am
by 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).
Code: Select all
; 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))
Re: SBCL to newLISP
Posted: Tue Jun 29, 2010 9:40 am
by wandernet
Code: Select all
;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)
Re: SBCL to newLISP
Posted: Tue Jun 29, 2010 12:35 pm
by Lutz
Re: SBCL to newLISP
Posted: Tue Jun 29, 2010 1:35 pm
by kanen
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:
;(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. :)
wandernet wrote:Code: Select all
;newLISP v.10.0.0
;on Win32 IPv4 UTF-8
(import "kernel32.dll" "GetTickCount")
Re: SBCL to newLISP
Posted: Tue Jun 29, 2010 5:03 pm
by Lutz
(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.
Re: SBCL to newLISP
Posted: Tue Jun 29, 2010 5:32 pm
by cormullion
Perhaps the Python uses built-in complex numbers...
I thought Michael's complex version was more fun:
Code: Select all
(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)
Re: SBCL to newLISP
Posted: Tue Jun 29, 2010 5:44 pm
by Tim Johnson
Also, why use multiple calls to 'set when one will do?
cheers
tim
Re: SBCL to newLISP
Posted: Tue Jun 29, 2010 6:07 pm
by m i c h a e l
And a single call to
set is faster, too:
Code: Select all
(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
Re: SBCL to newLISP
Posted: Tue Jun 29, 2010 6:45 pm
by Tim Johnson
I'll buy that one. I wonder if differences would change with more complex data types?
thanks
tim
Re: SBCL to newLISP
Posted: Wed Jun 30, 2010 5:49 pm
by itistoday
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.
Re: SBCL to newLISP
Posted: Wed Jun 30, 2010 7:15 pm
by 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 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
Re: SBCL to newLISP
Posted: Wed Jun 30, 2010 7:17 pm
by itistoday
Tim Johnson wrote: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.
Re: SBCL to newLISP
Posted: Wed Jun 30, 2010 8:00 pm
by Tim Johnson
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
Re: SBCL to newLISP
Posted: Thu Jul 01, 2010 1:21 am
by m i c h a e l
setf is faster than
set:
Code: Select all
(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
Re: SBCL to newLISP
Posted: Thu Jul 01, 2010 4:13 pm
by Tim Johnson
Michael, I've never used
setf like that. The docs say
setf is used when setting list or array references
but I see from my own console:
Curiouser and curiouser
Re: SBCL to newLISP
Posted: Fri Jul 02, 2010 6:15 pm
by m i c h a e l
Tim wrote:Michael, I've never used setf like that.
I don't normally use
setf for variable assignment either, but the comment from Greg (itistoday) sparked the new test. I was really surprised by the results. I assumed
setf was slower since it's used, as you quote:
newLISP Manual & Reference wrote:when setting list or array references
I wonder if there's a good reason to
not use
setf in place of
set and . . . wait. I forgot to test
setq:
Code: Select all
(define (test-setq-once) (setq a 1 b 2 c 3 d 4 e 5 f 6 g 7))
(define (test-setq-multiple)
(setq a 1)
(setq b 2)
(setq c 3)
(setq d 4)
(setq e 5)
(setq f 6)
(setq g 7)
)
(time (test-setq-once) 1000000) ;=> 381.148
(time (test-setq-multiple) 1000000) ;=> 525.763
So it looks like both
setq and
setf are faster than
set. I ran these tests multiple times, and the
q and
f versions are consistently faster. Lutz, should we be using
setq in place of
set for the slight speed increase?
m i c h a e l
Re: SBCL to newLISP
Posted: Fri Jul 02, 2010 6:19 pm
by itistoday
m i c h a e l wrote:So it looks like both setq and setf are faster than set. I ran these tests multiple times, and the q and f versions are consistently faster. Lutz, should we be using setq in place of set for the slight speed increase?
I don't think setq should be used at all, there's no reason for it as it's just an alias for setf (which is why you're seeing those results), and included for compatibility with old code.
I originally thought set was faster than setf for multiple assignments, but it seems like I must have made a mistake in those benchmarks, so setf is faster for everything. So, I don't know about you, but for consistency and speed I'm going to use setf for everything (unless I explicitly need to set on a symbol, which happens often enough, in which case there's no choice but to use set).
Re: SBCL to newLISP
Posted: Sat Jul 03, 2010 7:09 am
by xytroxon
setq setf !
syntax: (setq place-1 exp-1 [place-2 exp-2 ... ])
setq and setf work alike in newLISP and set the contents of a symbol, list, array or string or of a list, array or string place reference. Like set, setq and setf can take multiple argument pairs. Although both setq and setf point to the same built-in function internally, throughout this manual setq is used when setting a symbol reference and setf is used when setting list or array references.
-- xytroxon
Re: SBCL to newLISP
Posted: Sat Jul 03, 2010 4:27 pm
by itistoday
Yes, though the manual does use that convention for some reason, I don't see the point. I see it as adding confusion to my code and giving me one more thing to have to worry about (should I use setf or setq here?). There's no reason to burden yourself with unnecessary complexity.
Re: SBCL to newLISP
Posted: Sat Jul 03, 2010 5:10 pm
by m i c h a e l
Here's one more way to set variables:
Of course,
define cannot be used to do multiple assignments. I think Lutz said this form was designed for Scheme programmers to feel more at home.
m i c h a e l