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.