In a moments idleness, I decided to play with some more Mandelbrots and I re-wrote the one I had used a while back - actually, wrote it from 'scratch' by copying one I'd written in C a long time back and subsequently ported to my Linux based RTB Basic. I also decided to do some benchmarks, so made sure it would run un-changed in Applesoft, ehBasic and BBC Basic which are currently the 3 BASICs I can run on my Ruby 6502 SBC.
I wasn't aiming for speed - it's never going to be fast in BASIC, but I wanted to change the ASCII 'palette' and make sure it would run in as many BASICs I had to hand, so 2-character variable names, one statement per line. It won't run un-changed in my RTB, but that's not really important here, although note that RTB doesn't support multiple statements per line as there is no performance overhead to be gained in it from that trick.
There are 3 versions of the 6502 based BBC Basic, all from 1981 to 1983 and a 65C02 version in 1984 which was intended for the 65C02 2nd processor. I can run any of these on Ruby.
The results are not surprising: ehBasic is the slowest, Applesoft marginally faster, BBC Basic 4 (the 65C02 version) almost double the speed of ehBasic. For the parameters I used:
- ehBasic: 172 seconds
- Applesoft: 161 seconds
- BBC Basic 1-3: 124 seconds
- BBC Basic 4: 96 seconds
This is the code:
Code:
100 REM A BASIC, ASCII MANDELBROT
110 REM
120 REM This implementation copyright (c) 2019, Gordon Henderson
130 REM
140 REM Permission to use/abuse anywhere for any purpose granted, but
150 REM it comes with no warranty whatsoever. Good luck!
160 REM
170 C$ = ".,'~=+:;[/<&?oxOX# " : REM 'Pallet' Lightest to darkest...
180 SO = 1 : REM Set to 0 if your MID$() indexes from 0.
190 MI = LEN(C$)
200 MX = 4
210 LS = -2.0
220 TP = 1.25
230 XS = 2.5
240 YS = -2.5
250 W = 64
260 H = 48
270 SX = XS / W
280 SY = YS / H
290 Q = TIME
300 FOR Y = 0 TO H
310 CY = Y * SY + TP
320 FOR X = 0 TO W
330 CX = X * SX + LS
340 ZX = 0
350 ZY = 0
360 CC = SO
370 X2 = ZX * ZX
380 Y2 = ZY * ZY
390 IF CC > MI THEN GOTO 460
400 IF (X2 + Y2) > MX THEN GOTO 460
410 T = X2 - Y2 + CX
420 ZY = 2 * ZX * ZY + CY
430 ZX = T
440 CC = CC + 1
450 GOTO 370
460 PRINT MID$(C$, CC - SO, 1);
470 NEXT
480 PRINT
490 NEXT
500 PRINT
510 PRINT (TIME - Q) / 100
520 END
Note that the indentation is produced by the BBC Basic "LISTO 7" option, but otherwise I did use spaces in the code. BBC Basic and ehBasic preserves them, Applesoft strips them.
(And FWIW: While not a fair comparison by any standards, RTB on my Intel i3 desktop produces a 16-colour version in 640x480 graphics in 1.2 seconds...)
You can change the
LS (Left Side) and
TP (Top) to change the start location if you want to play with zooming in.
Here is the output:
Code:
............,,,,,,,,,,,,,,'''''''''''''''''''''''''',,,,,,,,,,,,,
...........,,,,,,,,,,,''''''''''''''''''''''''''''''''',,,,,,,,,,
..........,,,,,,,,,'''''''''''''''''''''''~~~~===~~~~''''',,,,,,,
.........,,,,,,,,'''''''''''''''''''''~~~~~~=+[&+==~~~~~''''',,,,
........,,,,,,,'''''''''''''''''''''~~~~~~~==+: ;+++~~~~~~''''',,
.......,,,,,,'''''''''''''''''''''~~~~~~~~===+:[ / [+~~~~~~''''''
......,,,,,,''''''''''''''''''''~~~~~~~~~===+:;/?o[:+==~~~~~'''''
......,,,,''''''''''''''''''''~~~~~~~~~====+:O/x <;:+==~~~~~~'''
.....,,,,''''''''''''''''''''~~~~~~~~~===++:# X/+====~~~~'''
.....,,,'''''''''''''''''''~~~~~~~~~==++++:;/X [:++====~~~''
....,,,'''''''''''''''''''~~~~~~~~==+++:::;[/ X/;:+++++==~~'
....,,''''''''''''''''''~~~~~~~===+[<&x[[? <&x o&//<;:::[[=~~
...,,'''''''''''''''''~~~~~~=====+:; &O /[</&/:=~
...,'''''''''''''''''~~~========++:;< x :=~
..,,'''''''''''''''~~=========+++:;/<O ;+==
..,'''''''''''''~~~=========++++:< ## X<;:+=
..''''''''''~~~~==:/++++++++::::;/x [;:=
.,''''''~~~~~~===+:X[;:;; ;;::;;[ o/=
.,''''~~~~~~~===++;<xXo<<X &<[[[/ X:+
.'''~~~~~~~=====+::[& <<& /:=
.'~~~~~~~~=====+::;/? oO :=
.'~~~~~~~====++/;[/o [+=
.~~~~~~=++++::;/???X #:+=
.==++:/::+:;;[[o :+==
&[:+==
.==++:/::+:;;[[o :+==
.~~~~~~=++++::;/???X #:+=
.'~~~~~~~====++/;[/o [+=
.'~~~~~~~~=====+::;/? oO :=
.'''~~~~~~~=====+::[& <<& /:=
.,''''~~~~~~~===++;<xXo<<X &<[[[/ X:+
.,''''''~~~~~~===+:X[;:;; ;;::;;[ o/=
..''''''''''~~~~==:/++++++++::::;/x [;:=
..,'''''''''''''~~~=========++++:< ## X<;:+=
..,,'''''''''''''''~~=========+++:;/<O ;+==
...,'''''''''''''''''~~~========++:;< x :=~
...,,'''''''''''''''''~~~~~~=====+:; &O /[</&/:=~
....,,''''''''''''''''''~~~~~~~===+[<&x[[? <&x o&//<;:::[[=~~
....,,,'''''''''''''''''''~~~~~~~~==+++:::;[/ X/;:+++++==~~'
.....,,,'''''''''''''''''''~~~~~~~~~==++++:;/X [:++====~~~''
.....,,,,''''''''''''''''''''~~~~~~~~~===++:# X/+====~~~~'''
......,,,,''''''''''''''''''''~~~~~~~~~====+:O/x <;:+==~~~~~~'''
......,,,,,,''''''''''''''''''''~~~~~~~~~===+:;/?o[:+==~~~~~'''''
.......,,,,,,'''''''''''''''''''''~~~~~~~~===+:[ / [+~~~~~~''''''
........,,,,,,,'''''''''''''''''''''~~~~~~~==+: ;+++~~~~~~''''',,
.........,,,,,,,,'''''''''''''''''''''~~~~~~=+[&+==~~~~~''''',,,,
..........,,,,,,,,,'''''''''''''''''''''''~~~~===~~~~''''',,,,,,,
...........,,,,,,,,,,,''''''''''''''''''''''''''''''''',,,,,,,,,,
............,,,,,,,,,,,,,,'''''''''''''''''''''''''',,,,,,,,,,,,,
(And yes, I checked it was identical for all versions!)
Extracting the BBC Basic floating point routines may be an interesting exercise at some point if I need faster FP routines. It's a 5 byte format though.
Cheers,
-Gordon