Wednesday, September 13, 2023

⚗ When CIRCLE feels too slow, try and test some triangle math

BAM will never be any kind of speed demon, BASIC code being transpiled at run-time to javascript.  But still, sometimes some things feel like they could be faster.

I've long felt that the CIRCLE statement in BASIC Anywhere Machine, as-is since I nabbed the wwwBASIC.js code back in Dec 2020, wasn't performing quite as fast as it could.

Not one to enjoy looking javascript in the eyeballs for any length of time, I sucked it up and looked just long enough to see too-much-for-my-liking trigonometry going on.

So I decided to apply the "test it with code" philosophy.  Not javascript code, but rather a BASIC subroutine that I'll implement in javascript when I'm ready for the bruising.

Triangle math related to triangles with right angles.  I remembered it faintly enough to think it would be useful, and knew just enough to go search the web.

If "C" is the corner of a triangle with a right angle, then the side "c" (right across from that right angle) has a length of (say a and b are the other sides):

length of "c" = square root ( "a" squared + "b" squared )

If "c" is the radius of a circle, then when "a" is the range of possible values for x, then we can calculate "b" as every value for y.  And we can do vice versa:  when "b" is the range of possible values for y, then we can calculate "a" as every value for x.  (we need to calculate both ways to not miss any pixels around the circumference of a circle.)

Lo and behold, my BASIC subroutine is twice (plus a hair or two) as fast as the CIRCLE statement's implementation in wwwBASIC.

You may find the source code for this program useful for your own testing with your BASIC implementation(s).

The program takes stop-watch-like time of drawing 50 circles with the subroutine, then does the same thing using the CIRCLE statement.  Information is printed on the screen, and the program keeps repeating all of this in an endless loop.  So we can see the time differences cumulatively over time.

The circle on the left (c1)  is drawn with the "triangle math" BASIC subroutine.
The circle on the right (c2) is drawn with the CIRCLE statement.

The "count" indicates the total number of circle-drawing iterations.  The number indicates the number of times both circles have been drawn.  1 means each circle was drawn once.

Time is measured in the number of seconds taken to draw all of the circles for each approach.  So for that count of circles for each approach, the c1 circles cumulatively took 46 seconds, and the c2 circles cumulatively took 96 seconds.


Aside: about that "aspect_ratio" thing, which most folk likely wouldn't need.

That's needed in BASIC Anywhere Machine to maintain compatibility with GW-BASIC screen modes (GW-BASIC being a high priority.)

If you have access to GW-BASIC (run GW-BASIC at the Internet Archive in a web-based emulator, or whatever that is), write a program that draws a circle and a box around it, then run it in the various GW-BASIC screen modes.  You'll see the CIRCLE always stays a circle, but the box is sometimes a square, but often a rectangle.  That's because in the various screen modes, pixel height is greater by some ratio than pixel width.  CIRCLE in GW-BASIC has been implemented in such a way that it adjusts the circle as per the aspect ratio of pixel height versus width.



No comments:

Post a Comment

🖥 Saucer Zap

This program is a port and mod of a QBJS program by James D Jarvis (shared with the QB64PE community and discussed in this thread ). That pr...