(loop for y from 1 to 1.1 by 0.1 do
(loop for x from 2 to 1 by 0.04 do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (< (abs
(setq z (+ (* z z) a)))
2)
while (> (decf c) 32))
(princ (codechar c))))
(format t "~%"))
I tried to make it as short as possible and it is some chars shorter than
the Java program, if written in one line without much spaces. With CLISP,
the program is only 4 times slower than the Java program. Nice result, I
didn't expect this with my unoptimized program and using complex variables.

Frank Buß, f...@frankbuss.de
http://www.frankbuss.de, http://www.it4systems.de
> Based on a Java program ( http://tinyurl.com/57smz ) I've
> implemented a Lisp program for showing the Mandelbrot set:
>
> (loop for y from 1 to 1.1 by 0.1 do
> (loop for x from 2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (< (abs
> (setq z (+ (* z z) a)))
> 2)
> while (> (decf c) 32))
> (princ (codechar c))))
> (format t "~%"))
>
> I tried to make it as short as possible and it is some chars shorter
> than the Java program, if written in one line without much
> spaces. With CLISP, the program is only 4 times slower than the Java
> program. Nice result, I didn't expect this with my unoptimized
> program and using complex variables.
If I change it a little bit
(defun mandel ()
(loop for y from 1 to 1.1 by 0.1 do
(loop for x from 2 to 1 by 0.04 do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (codechar c))))
(princ #\Newline)))
and compile it with CMUCL (19apre3) then it's actually faster by a
factor of 1.3 than the Java (1.5.0beta2) version on my
laptop. Cool... :)

"Lisp doesn't look any deader than usual to me."
(David Thornley, reply to a question older than most languages)
Real email: (replace (subseq "spam...@agharta.de" 5) "edi")
> If I change it a little bit
>
> (defun mandel ()
> (loop for y from 1 to 1.1 by 0.1 do
> (loop for x from 2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (and (< (abs
> (setq z (+ (* z z) a)))
> 2)
> (> (decf c) 32)))
> (princ (codechar c))))
> (princ #\Newline)))
>
> and compile it with CMUCL (19apre3) then it's actually faster by a
> factor of 1.3 than the Java (1.5.0beta2) version on my
> laptop. Cool... :)
Faster even if you start cheating a little:
(defun mandel ()
(loop for y from 1 to 1.1 by 0.1 do
(loop for x from 2 to 1 by 0.04 do
(let* ((z (complex x y))
(a z))
(loop for c in '#.(loop for c downfrom 126 above 32
collect (codechar c))
while (< (abs
(setq z (+ (* z z) a)))
2)
finally (princ c))))
(princ #\Newline)))
But I'll stop now... :)
Man, that's rad! Just pasted that puppy in my REPL and boom! ASCII art
Mandlebrot. Nice.
Peter

Peter Seibel pe...@javamonkey.com
Lisp is the red pill.  John Fraser, comp.lang.lisp
Very cool. How did you get the ascii characters though? I don't see
them anywhere in the code. All I see that might even have something to
do with it is
(princ (codechar c))))

May the Source be with you.
neo88 (Philip Haddad)
> Based on a Java program ( http://tinyurl.com/57smz ) I've implemented a
> Lisp program for showing the Mandelbrot set:
>
> (loop for y from 1 to 1.1 by 0.1 do
> (loop for x from 2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (< (abs
> (setq z (+ (* z z) a)))
> 2)
> while (> (decf c) 32))
> (princ (codechar c))))
> (format t "~%"))
> ...
And a scheme version:
(define (mandel)
(do ((y 1 (+ y 0.1))) ((> y 1))
(do ((x 2 (+ x 0.04))) ((> x 1))
(let ((a (makerectangular x y)))
(let loop ((z a) (c 126))
(let ((q (+ a (* z z))))
(if (and (< (magnitude q) 2) (> c 32))
(loop q (sub1 c))
(display (integer>char c)))))))
(newline)))
Aziz,,,
> Very cool. How did you get the ascii characters though? I
> don't see them anywhere in the code. All I see that might
> even have something to do with it is
>
> (princ (codechar c))
Spot the magic numbers 32 and 126
(charcode #\space) => 32
(charcode #\~) => 126
the code commits itself to the ASCII character set.

Alan Crowe
Edinburgh
Scotland
> (loop for c in '#.(loop for c downfrom 126 above 32
> collect (codechar c))
this is really nice, I didn't know the reader macros before.
Ok, and now with TGA output, in the size of my screen for a new wallpaper
(see http://www.frankbuss.de/tmp/mandelbrot.jpg for a quality reduced
version). The program finished in 346 seconds run time, but that's mainly
because the algorithm is not optimized. There is a recursive algorithm
which calculates only 4 border points of a rectangle and fills it, if it
has the same color, which should reduce the running time to less than 10
seconds, I think, because most time the algorithm is spending in the
black area.
(defun mandelbrot ()
(let* ((width 1600)
(height 1024)
(x0 0.25)
(y0 0.5)
(x1 0.43)
(y1 0.71)
(image
(makearray (list width height 3)
:elementtype '(unsignedbyte 8)
:initialelement 0)))
(loop for y from 0 to (1 height) do
(loop for x from 0 to (1 width) do
(let* ((c 60)
(z (complex
(float (+ (* ( x1 x0) (/ x width)) x0))
(float (+ (* ( y1 y0) (/ y height)) y0))))
(a z))
(loop while (and (< (square
(setq z (+ (* z z) a)))
4)
(> (decf c) 0)))
(if (> c 0) (progn
(setf (aref image x y 0)
(mod (* 4 c) 256))
(setf (aref image x y 1)
(mod (* 8 c) 256))
(setf (aref image x y 2)
(mod (* 13 c) 256)))))))
(writetga image "mandelbrot.tga")))
(defun square (z)
(+ (* (realpart z) (realpart z)) (* (imagpart z) (imagpart z))))
(defun writetga (image filename)
(let* ((dimension (arraydimensions image))
(width (nth 0 dimension))
(height (nth 1 dimension)))
(withopenfile
(tga filename
:direction :output
:ifexists :supersede
:elementtype 'unsignedbyte)
(dolist (byte (list 0 0 2 0 0 0 0 0 0 0 0 0
(mod width 256) (floor width 256)
(mod height 256) (floor height 256) 24 0))
(writebyte byte tga))
(loop for y from 0 to (1 height) do
(loop for x from 0 to (1 width) do
(writebyte (aref image x y 0) tga)
(writebyte (aref image x y 1) tga)
(writebyte (aref image x y 2) tga))))))
> (defun mandel ()
> (loop for y from 1 to 1.1 by 0.1 do
> (loop for x from 2 to 1 by 0.04 do
> (let* ((z (complex x y))
> (a z))
> (loop for c in '#.(loop for c downfrom 126 above 32
> collect (codechar c))
> while (< (abs
> (setq z (+ (* z z) a)))
> 2)
> finally (princ c))))
> (princ #\Newline)))
>
Not the final iteration:
(loop for y from 1 to 1.1 by 0.1 do
(loop for x from 2 to 1 by 0.04 do
(loop with a = (complex x y)
for z = a then (+ (* z z) a)
for c in '#.(loop for c downfrom 126 downto 32
collect (codechar c))
while (< (* z (conjugate z) 4)
finally (princ c)))
(princ #\Newline))
> But I'll stop now... :)

"Brown the leaves, gray the sky, the horizont  white."
 Unknown
I really should get back to my CL version that does images. My movie
is still on my website. But that was done with a combination of Perl
and C.
The first ASCII art were done in EBCDIC!

__Pascal Bourguignon__ http://www.informatimago.com/
There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him.  Robert Heinlein
Here is my attempt to allow the user to zoom
in on various parts of the picture.
After each drawing you can select a quadrant to
zoom into

2  1

+

3  4

However, as you zoom it does not seem to show
any extra detail. Is there something wrong with
my function?
(defun mandel ()
(let (( x0 2.0)
( y0 1.0)
( x1 1.0)
( y1 1.1)
midx
midy
)
(loop while t do
(window x0 y0 x1 y1)
(setf midx (/ (+ x1 x0) 2.0)
midy (/ (+ y1 y0) 2.0))
(format t "quadrant: ")
(multiplevaluesetq ( x0 y0 x1 y1 )
(case (read)
( 1 (values midx midy x1 y1))
( 2 (values x0 midy midx y1))
( 3 (values x0 y0 midx midy))
( 4 (values midx y0 x1 midy))
( t (values x0 y0 x1 y1)))))))
(defun window ( x0 y0 x1 y1)
(let (( dx (/ ( x1 x0) 30.0))
( dy (/ ( y1 y0) 30.0)))
(format t "x0=~A y0=~A x1=~A y1=~A dx=~A dy=~A~%"
x0 y0 x1 y1 dx dy)
(loop for y from y0 to y1 by dy do
(loop for x from x0 to x1 by dx do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (codechar c))))
(princ #\Newline))))

3  4

+

2  1

i've modified the code to decrement y instead of increment.
and it seems to work well... except that
when dx or dy becomes in the range of dx=1.5894572e8 dy=1.5894572e8
very strange things happen... i wonder is this a problem with
percision on the x86?
x0=0.04844904 y0=0.80464506 x1=0.048448563 y1=0.80464554
dx=1.5894572e8 dy=1.5894572e8
give it a try...
(defun mandel ()
(let (( x0 2.0) ;;( x0 2.0)
( y0 2.0) ;;( y0 1.0)
( x1 2.0) ;;( x1 1.0)
( y1 2.0) ;;( y1 1.1)
midx
midy
)
(loop while t do
(window x0 y0 x1 y1)
(setf midx (/ (+ x1 x0) 2.0)
midy (/ (+ y1 y0) 2.0))
(format t "quadrant: ")
(multiplevaluesetq ( x0 y0 x1 y1 )
(case (read)
( 1 (values midx midy x1 y1))
( 2 (values x0 midy midx y1))
( 3 (values x0 y0 midx midy))
( 4 (values midx y0 x1 midy))
( t (values x0 y0 x1 y1)))))))
(defun window ( x0 y0 x1 y1)
(let (( dx (/ ( x1 x0) 30.0))
( dy (/ ( y1 y0) 30.0)))
(format t "x0=~A y0=~A x1=~A y1=~A dx=~A dy=~A~%"
x0 y0 x1 y1 dx dy)
(princ "2")
(loop for x from x0 to x1 by dx do
(princ ""))
(princ "1")
(princ #\Newline)
(loop for y from y1 downto y0 by dy do
(princ "")
(loop for x from x0 to x1 by dx do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (codechar c))))
(princ "")
(princ #\Newline))
(princ "3")
(loop for x from x0 to x1 by dx do
(princ ""))
(princ "4")
(princ #\Newline)))
(compile 'mandel)
(compile 'window)
(mandel)
jim
> i'm not sure how the algorithm is supposed to be
> selecting the character to display, but it does not
> seem very adapatable if i try to zoom in on the
> boundary of the mandelbrot set.
>
> Here is my attempt to allow the user to zoom
> in on various parts of the picture.
>
> After each drawing you can select a quadrant to
> zoom into
>
> 
> 2  1
> 
> +
> 
> 3  4
> 
>
> However, as you zoom it does not seem to show
> any extra detail. Is there something wrong with
> my function?
works well on my computer. But the quadrants are mirrored at the yaxis,
because you test at negative y coordinates first. Try this:
4322321221121243141341
This zooms 1 : 4,000,000, but after the last '1' the program ended in an
endless loop, because looks like my floating point precision is limited
to 8 significant digits with your program.
e.g., (mandel 2 4 1 1)
after the zooming, it goes into interactive mode.
Yes there seems to be a limitation around dx=1e8...
curious.
jim
(defun mandel ( &rest quadrants)
(let (( x0 2.0)
( y0 2.0)
( x1 2.0)
( y1 2.0))
(dolist ( q quadrants)
(multiplevaluesetq ( x0 y0 x1 y1 )
(selectquadrant q x0 y0 x1 y1 )))
(loop while t do
(drawquadrant x0 y0 x1 y1)
(format t "quadrant: ")
(multiplevaluesetq ( x0 y0 x1 y1 )
(selectquadrant (read) x0 y0 x1 y1)))))
(defun selectquadrant ( q x0 y0 x1 y1)
(let (( midx (/ (+ x1 x0) 2.0))
( midy (/ (+ y1 y0) 2.0)))
(case q
( 1 (values midx midy x1 y1))
( 2 (values x0 midy midx y1))
( 3 (values x0 y0 midx midy))
( 4 (values midx y0 x1 midy))
( t (values x0 y0 x1 y1)))))
(defun drawquadrant ( x0 y0 x1 y1)
(let (( dx (/ ( x1 x0) 30.0))
( dy (/ ( y1 y0) 30.0)))
(format t "x0=~A y0=~A x1=~A y1=~A dx=~A dy=~A~%"
x0 y0 x1 y1 dx dy)
(princ "2")
(loop for x from x0 to x1 by dx do
(princ ""))
(princ "1")
(princ #\Newline)
(loop for y from y1 downto y0 by dy do
(princ "")
(loop for x from x0 to x1 by dx do
(let* ((c 126)
(z (complex x y))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(princ (codechar c))))
(princ "")
(princ #\Newline))
(princ "3")
(loop for x from x0 to x1 by dx do
(princ ""))
(princ "4")
(princ #\Newline)))
(compile 'mandel)
(compile 'selectquadrant)
(compile 'drawquadrant)
(mandel)
> you can now call (mandel...) with the zoom
> quadrants
>
> e.g., (mandel 2 4 1 1)
>
> after the zooming, it goes into interactive mode.
> Yes there seems to be a limitation around dx=1e8...
> curious.
you can replace all numbers with doublefloats, then you can go until
dx= doublefloatepsilon (something around 1d16 on my computer) and then
this works:
(mandel 1 3 2 3 2 3 3 4 1 1 4 4 1 3 3 1 3 3 3 1 4 4 4 1 3 4 4 4 3 3 3 4 3
4 2 3 4 4 1 1 2 4 3)
Zooming 1:8796093022208. That's like zooming from the earth fullscreen to
a flake of one hair of a person fullscreen :)
(defun mandel ( &rest quadrants)
(let (( x0 2d0)
( y0 2d0)
( x1 2d0)
( y1 2d0))
(dolist ( q quadrants)
(multiplevaluesetq ( x0 y0 x1 y1 )
(selectquadrant q x0 y0 x1 y1 )))
(loop while t do
(drawquadrant x0 y0 x1 y1)
(format t "quadrant: ")
(multiplevaluesetq ( x0 y0 x1 y1 )
(selectquadrant (read) x0 y0 x1 y1)))))
(defun selectquadrant ( q x0 y0 x1 y1)
(let (( midx (/ (+ x1 x0) 2d0))
( midy (/ (+ y1 y0) 2d0)))
(case q
( 1 (values midx midy x1 y1))
( 2 (values x0 midy midx y1))
( 3 (values x0 y0 midx midy))
( 4 (values midx y0 x1 midy))
( t (values x0 y0 x1 y1)))))
(defun drawquadrant ( x0 y0 x1 y1)
(let (( dx (/ ( x1 x0) 30d0))
( dy (/ ( y1 y0) 30d0)))

346 seconds = 5 min 46 seconds. I ran this program for about seven
minutes I'd say, on CMUCL 18e, and all it did was call the GC
endlessly until I intruppted it from Emacs. I also tried it in Allegro
CL Trial, and it instantly overflowed the allowed GC allocation.
So does this write a tga file to the directory that the program is in,
so that you can open it later, or does it write the file directly to
the screen?
> 346 seconds = 5 min 46 seconds. I ran this program for about seven
> minutes I'd say, on CMUCL 18e, and all it did was call the GC
> endlessly until I intruppted it from Emacs. I also tried it in Allegro
> CL Trial, and it instantly overflowed the allowed GC allocation.
in CMUCL you should try (compile 'mandelbrot) and (compile 'square) first,
it greatly enhances the speed. And you can reduce the output size by
reducing the 1600x1024 size.
> So does this write a tga file to the directory that the program is in,
> so that you can open it later, or does it write the file directly to
> the screen?
it writes it in the current working directory. Perhaps you should write
somthing like "/tmp/mandelbrot.tga" to write it to a place you know where
it is.
> 346 seconds = 5 min 46 seconds. I ran this program for about seven
> minutes I'd say, on CMUCL 18e, and all it did was call the GC
> endlessly until I intruppted it from Emacs.
Did you compile it?
> Ok, and now with TGA output
and finally: ASCII output in an MPEG animation :)
http://www.mynetcologne.de/~ncbuszfr/mandelbrot.mpg (4.9 MB)
This was easy: first I screen captured the output of char 33 to 126,
saved it to TGA and created a Lisp vector with this Lisp program from it:
(defun charset ()
(withopenfile (chars "/tmp/chars.tga" :elementtype 'unsignedbyte)
(loop for c from 0 to 93 do
(princ "(")
(princ #\Newline)
(loop for y from 11 downto 0 do
(fileposition chars (+ 18 (* y 752) (* c 8)))
(princ "\"")
(loop for x from 0 to 7 do
(if (= 255 (readbyte chars))
(princ "*")
(princ " ")))
(princ "\" ")
(princ #\Newline))
(princ ")")
(princ #\Newline))))
Which looked like this:
(defconstant *charset*
(makearray
'(94 12)
:initialcontents
'((
" "
" ** "
" **** "
" **** "
" **** "
" ** "
" ** "
" "
" ** "
" ** "
" "
" "
)
(
" "
" ** ** "
" ** ** "
" ** ** "
" * * "
" "
" "
" "
" "
" "
" "
" "
)
...
Then I wrote a litte class, which simulates a terminal output with TGA
and interpolates between a zooming step (see below, full program:
http://www.frankbuss.de/tmp/mandelbrot.lisp.txt ). The 344 TGAs were
converted with http://dmr.ath.cx/gfx/tga2avi/ to a 107 MB AVI file and
then with http://www.winload.de/download.php?programm_id=23273 to MPG.
(defun mandel (&rest quadrants)
(let ((x0 2d0)
(y0 2d0)
(x1 2d0)
(y1 2d0)
(i 0)
(steps 8))
(dolist (q quadrants)
(let ((x0old x0)
(y0old y0)
(x1old x1)
(y1old y1))
(multiplevaluesetq (x0 y0 x1 y1)
(selectquadrant q x0 y0 x1 y1))
(loop for j from 0 to (1 steps) do
(format t "calculating image ~S of ~S~%" (1+ i) (* steps
(length quadrants)))
(drawquadrant i
(+ (* (/ ( x0 x0old) steps) j) x0old)
(+ (* (/ ( y0 y0old) steps) j) y0old)
(+ (* (/ ( x1 x1old) steps) j) x1old)
(+ (* (/ ( y1 y1old) steps) j) y1old))
(incf i))))))
(defun selectquadrant (q x0 y0 x1 y1)
(let ((midx (/ (+ x1 x0) 2d0))
(midy (/ (+ y1 y0) 2d0)))
(case q
(1 (values midx midy x1 y1))
(2 (values x0 midy midx y1))
(3 (values x0 y0 midx midy))
(4 (values midx y0 x1 midy))
(t (values x0 y0 x1 y1)))))
(defun drawquadrant (i x0 y0 x1 y1)
(let ((steps 30)
(ti (makeinstance 'terminalimage)))
(charout ti #\2)
(loop for x from 0 to steps do
(charout ti #\))
(charout ti #\1)
(newline ti)
(loop for y from 0 to steps do
(charout ti #\)
(loop for x from 0 to steps do
(let* ((c 126)
(z (complex
(+ (* (/ ( x1 x0) steps) x) x0)
(+ (* (/ ( y1 y0) steps) y) y0)))
(a z))
(loop while (and (< (abs
(setq z (+ (* z z) a)))
2)
(> (decf c) 32)))
(charout ti (codechar c))
))
(charout ti #\)
(newline ti))
(charout ti #\3)
(loop for x from 0 to steps do
(charout ti #\))
(charout ti #\4)
(newline ti)
(writetga ti (format nil "/tmp/t~S.tga" i))))
(defclass terminalimage ()
((cols :initarg cols :initform 33)
(rows :initarg rows :initform 33)
(cursorx :initform 0)
(cursory :initform 0)
width height image))
(defmethod charout ((ti terminalimage) c)
(let ((index ( (charcode c) 33))
(x0 (* 8 (slotvalue ti 'cursorx)))
(y0 (* 12 (slotvalue ti 'cursory))))
(if (and (<= 0 index) (< index 94))
(loop for y from 0 to 11 do
(let ((charline (aref *charset* index y)))
(loop for x from 0 to 7 do
(if (not (eq #\Space (elt charline x)))
(setf
(aref (slotvalue ti 'image)
(+ y y0) (+ x x0))
1)))))))
(incf (slotvalue ti 'cursorx)))
(defmethod newline ((ti terminalimage))
(setf (slotvalue ti 'cursorx) 0)
(incf (slotvalue ti 'cursory)))
(defmethod initializeinstance :after ((ti terminalimage) &key)
(let ((width (* (slotvalue ti 'cols) 8))
(height (* (slotvalue ti 'rows) 12)))
(setf (slotvalue ti 'width) width)
(setf (slotvalue ti 'height) height)
(setf (slotvalue ti 'image) (makearray
(list height width)
:elementtype '(unsignedbyte 1)
:initialelement 0))))
(defmethod writetga ((ti terminalimage) filename)
(let ((width (slotvalue ti 'width))
(height (slotvalue ti 'height)))
(withopenfile
(tga filename
:direction :output
:ifexists :supersede
:elementtype 'unsignedbyte)
(dolist (byte (list 0 0 2 0 0 0 0 0 0 0 0 0
(mod width 256) (floor width 256)
(mod height 256) (floor height 256) 24 0))
(writebyte byte tga))
(loop for y from (1 height) downto 0 do
(loop for x from 0 to (1 width) do
(let ((color
(if (= (aref (slotvalue ti 'image) y x) 1)
255
0)))
(writebyte color tga)
(writebyte color tga)
(writebyte color tga)))))))
> Based on a Java program ( http://tinyurl.com/57smz ) I've implemented a
> Lisp program for showing the Mandelbrot set:
>
> (loop for y from 1 to 1.1 by 0.1 do
> (loop for x from 2 to 1 by 0.04 do
> (let* ((c 126)
> (z (complex x y))
> (a z))
> (loop while (< (abs
> (setq z (+ (* z z) a)))
> 2)
> while (> (decf c) 32))
> (princ (codechar c))))
> (format t "~%"))
(...)
... and an Emacs Lisp version:
(require 'cl)
(defun compmult (a b) ; a and b are lists (x y) corresponding to x + yi
(list ( (* (car a) (car b))
(* (cadr a) (cadr b)))
(+ (* (car a) (cadr b))
(* (cadr a) (car b)))))
(defun compadd (z1 z2)
(list (+ (car z1) (car z2))
(+ (cadr z1) (cadr z2))))
(defun compabs (z)
(sqrt (+ (* (car z) (car z))
(* (cadr z) (cadr z)))))
(let* ((buffername (getbuffercreate "*Mandelbrot*")))
(switchtobuffer buffername)
(erasebuffer)
(loop for y from 1 to 1.1 by 0.1 do
(loop for x from 2 to 1 by 0.04 do
(let* ((c 126)
(z (list x y))
(a z))
(loop while (< (compabs
(setq z (compadd (compmult z z) a)))
2)
while (> (decf c) 32))
(insert (princ (makechar 'ascii c)))))
(newline)))
I had to create some helper functions for handling the complex
values. I guess I could've used the calc package's functions
concerning complex numbers, but they looked awkward to use without
running the calculator as far as I could see. Besides, not all use
the calc package anyway.
Eivind L. Rygge
Oslo, Norway
PS! First post in comp.lang.lisp :)
Hello to all who attended the Lisp & Scheme Workshop here in Oslo this summer.
Why not mere cons cells?
(defun realpart (c) (car c))
(defun imagpart (c) (cdr c))
(defun complex (r &optional (i 0)) (cons r i))
Or, slightly less COMMONLISP, but slightly more efficient:
(defmacro realpart (c) `(car ,c))
(defmacro imagpart (c) `(cdr ,c))
(defmacro complex (r &optional (i 0)) `(cons ,r ,i))
> (defun compmult (a b)
> (list ( (* (car a) (car b))
> (* (cadr a) (cadr b)))
> (+ (* (car a) (cadr b))
> (* (cadr a) (car b)))))
(defun c* (&rest args)
(reduce (lambda (a b)
(complex ( (* (realpart a)(realpart b))
(* (imagpart a)(imagpart b)))
(+ (* (realpart a)(imagpart b))
(* (imagpart a)(realpart b)))))
args
:initalvalue (complex 1 0)))
> (defun compadd (z1 z2)
> (list (+ (car z1) (car z2))
> (+ (cadr z1) (cadr z2))))
(defun c+ (&rest args)
(reduce (lambda (a b)
(complex (+ (realpart a)(realpart b))
(+ (imagpart a)(imagpart b))))
args
:initalvalue (complex 0 0)))
> (defun compabs (z)
> (sqrt (+ (* (car z) (car z))
> (* (cadr z) (cadr z)))))
(defun cabs (c)
(sqrt (+ (* (realpart c)(realpart c))
(* (imagpart c)(imagpart c)))))
> (let* ((buffername (getbuffercreate "*Mandelbrot*")))
> (switchtobuffer buffername)
> (erasebuffer)
> (loop for y from 1 to 1.1 by 0.1 do
> (loop for x from 2 to 1 by 0.04 do
> (let* ((c 126)
> (z (list x y))
> (a z))
> (loop while (< (compabs
> (setq z (compadd (compmult z z) a)))
> 2)
> while (> (decf c) 32))
> (insert (princ (makechar 'ascii c)))))
> (newline)))
>
>
> I had to create some helper functions for handling the complex
> values. I guess I could've used the calc package's functions
> concerning complex numbers, but they looked awkward to use without
> running the calculator as far as I could see. Besides, not all use
> the calc package anyway.
>
> Eivind L. Rygge
> Oslo, Norway
>
> PS! First post in comp.lang.lisp :)
> Hello to all who attended the Lisp & Scheme Workshop here in Oslo this summer.

__Pascal Bourguignon__ http://www.informatimago.com/
Nobody can fix the economy. Nobody can be trusted with their finger
on the button. Nobody's perfect. VOTE FOR NOBODY.
> ... and an Emacs Lisp version:
<URL:http://www.gnusoftware.com/Emacs/Lisp/mandel.el> might be of interest.

Dave Pearson
http://www.davep.org/lisp/
> PS! First post in comp.lang.lisp :)
> Hello to all who attended the Lisp & Scheme Workshop here in Oslo this summer.
Hi. ;)

Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
> does complex do something different if you
> give it two double floats? i.e., is there a
> difference between (complex 1.0 1.0) and (complex 1d0 1d0)
yes. If I'm doing this in CLISP:
(expt (/ (complex 1 1) 1e30) 2)
I got a SIMPLEFLOATINGPOINTUNDERFLOW error, but if I do this:
(expt (/ (complex 1d0 1d0) 1e30) 2)
I got #C(0.0d0 1.9999999398101364d60) (and a warning, which is not
generated if I use 1d30 instead of 1e30).