Console Mandelbrot in FORTH

by

in
The Mandelbrot Set printed out in a console with text.

I really like to play around with FORTH. It’s a “weird” programming language compared to all the other ones I’ve learned over time. There are already many articles out there about why you should give it a try, the best probably being this one at Hackaday.

One little program that is often demonstrate on old computers is a BASIC program to compute the Mandelbrot Set in the console. I thought I’d try my hand in “converting” the program to FORTH.

Here’s my version, taken from a gist I wrote earlier this year.

\ from proposal http://www.forth200x.org/fvalue.html
variable %var
: to 1 %var ! ;
: fvalue create f, does> %var @ if f! else f@ then 0 %var ! ;

0e0 fvalue i3
0e0 fvalue r3

59 value x1
21 value y1
-1e0 fvalue i1 
1e0 fvalue i2
-2e0 fvalue r1
1e0 fvalue r2
r2 r1 f- x1 s>f f/ fvalue s1 \ L30
i2 i1 f- y1 s>f f/ fvalue s2 \ L31

0e0 fvalue a
0e0 fvalue b
: single_iter { F: z1 F: z2 } ( F: z1 F: z2 -- F: z1' F: z2' F: mag )
  z1 fdup f* to a \ L90
  z2 fdup f* to b \ L91
  a b f- r3  f+ \ z1 \ L111
  2e0 z1 z2 f* f* i3 f+ \ z2 L110
  a b f+ \ mag \ line 100
;

: print_char ( F: x F: y -- )
  30 \ push the max in case we don't exit early
  30 0 do                          \ L80
    single_iter
    4e0 f> if drop i leave then
  loop                             \ L120
  fdrop fdrop \ clean z1 and z2
  62 swap - emit                   \ L130
;

: calc_i3 { y }
  i1 s2 y s>f f* f+ to i3 \ L50
;

: calc_r3 { x }
  r1 s1 x s>f f* f+ to r3 \ L70
;

: mandel
cr \ always start on a fresh clean line
y1 0 do                         \ L40
  i calc_i3
  x1 0 do                       \ L60
    i calc_r3
    r3 i3 print_char
  loop                            \ L140
  cr                              \ L150
loop                              \ L160
;

mandel

That prints out something like the screenshot at the top of this post.

The “L##” comments roughly refer to the lines in the BASIC version, if you’d like to compare the two. I tried to keep the memory usage and general complexity as equal as possible – that’s why there are so many value and fvalue variables. I’ve seen some examples that use the stack more but are harder to read and have to recompute a lot of things that the BASIC version doesn’t.

Here’s the original BASIC version:

10 x1=59
11 y1=21
20 i1=-1.0
21 i2=1.0
22 r1=-2.0
23 r2=1.0
30 s1=(r2-r1)/x1
31 s2=(i2-i1)/y1
40 for y=0  to y1
50 i3=i1+s2*y
60 for x=0 to x1
70 r3=r1+s1*x
71 z1=r3
72 z2=i3
80 for n=0 to 29
90 a=z1*z1
91 b=z2*z2
100 if a+b>4.0 goto 130
110 z2=2*z1*z2+i3
111 z1=a-b+r3
120 next n
130 print chr$(62-n);
140 next x
150 print
160 next y
170 end

I’m consistently intrigued by FORTH, so I’ll probably be sharing more programs and thoughts. I wrote a short explanation of the “polyfill” in the first four lines of the FORTH version is actually a great dive into the language’s extensibility.