Skip to navigation

BBC Micro Elite

The sine, cosine and arctan tables

The lookup tables used for the planet-drawing trigonometric functions

References: SNE, ARCTAN, ACT

The SNE table contains lookup values for sine and cosine. These values are used when drawing circles and suns, as the small angle approximation that we use when rotating ships in space isn't accurate enough for describing entire circles. For this, we need to be able to look up the sine and cosine of any angle, not just small ones, and for that we need a lookup table.

The ACT table, meanwhile, contains lookup values for arctan. This is used when drawing the meridians and equators on planets in part 2 of PL9.

Let's have a look at how these tables work (see the deep dives on "Drawing circles" and "Drawing the sun" for more details on how the sine and cosine tables are actually used.)

Sine table

We use the sine table like this. To calculate the following:

  sin(theta) * 256

where theta is in radians, we look up the value in:

  SNE + (theta * 10)

Here's how this works. The value at byte number (theta * 10) is:

  256 * ABS(SIN((theta * 10 / 64) * 2 * PI))

rounded to the nearest integer. If we expand the part that we pass to SIN():

  (theta * 10 / 64) * 2 * PI =  (theta / 6.4) * 2 * PI
                             =~ (theta / 6.4) * 6.28
                             =~ theta

then substituting this into the above, we can see that the value at byte (theta * 10) is approximately:

  256 * ABS(SIN(theta))

Cosine table

So that's the sine lookup, but what about the cosine? To calculate the following:

  cos(theta) * 256

where theta is in radians, we look up the value in:

  SNE + ((theta * 10) + 16) mod 32

How does this work? Well, because of the way sine and cosine work in terms of right-angled triangles, the following holds true (using degrees for a second as it's easier to picture):

  cos(theta) = sin(90 − theta) = sin(90 + theta)

So to get the cosine value, we just need to look up the sine of 90 + theta.

The 32 entries in the sine table cover half a circle, as they go from sin(0) to sin(31/64 * 2 * PI) and there are 2 * PI radians in a circle, so if 32 entries covers half a circle, 90 degrees is a half of that, or 16.

So to get the cosine, we look up the following value, applying mod 32 so the table lookup wraps around correctly if the index falls over the end:

  SNE + ((theta * 10) + 16) mod 32

It's not 100% accurate, but it's easily good enough for our needs.

Arctan table

To calculate the following:

  theta = arctan(t)

where 0 <= t < 1, we look up the value in:

  ACT + (t * 32)

The result will be an integer representing the angle in radians, with 256 representing a full circle of 2 * PI radians.

The ACT table contains arctan values for arguments less than one - in other words, it contains values for arctan(0) through arctan(31/32), or angles in triangles where the length of the opposite is less than the length of the adjacent, so the angle is less than 45 degrees. This means the table contains values in the range 0 to 31.

The table does not support values of t >= 1 or t < 0 directly, but we can use the following calculations instead:

  • For t > 1, arctan(t) = 64 - arctan(1 / t)
  • For t < 0, arctan(-t) = 128 - arctan(t)

If t < -1, we can do the first one to get arctan(|t|), then the second to get arctan(-|t|).

The first one follows from the fact that arctan(t) + arctan(1 / t) = PI / 2, and we represent PI / 2 by 64 in our model.

The second one follows from the fact that arctan(-t) = PI - arctan(t) for the range 0 < arctan(t) < PI, and we represent PI by 128 in our model.