# 9.2: “Yes, I’d Like a Table for 360, Please”

Consider the common C trig function, sin(). Not much to it, really. You pass it an argument and you get back the sine of the argument. But how is it implemented? It could be implemented as a Taylor Series expansion that requires several multiplies and adds. A single sine computation won’t take long but what if you need to do millions of them? All of those multiplies and adds add up, so to speak. Consider the following problem: You need to get the sine of an angle specified to the nearest degree, and fast. Basically, you have 360 possible answers (0 degrees through 359 degrees)1. Now suppose you create an array of 360 values which consists of the sine of each angle in one degree increments, starting at 0 degrees and working up to 359 degrees. It might look something like this:

double sine_table[] = { 0.0, 0.01745, 0.034899, 0.05234,
/* and so on to the last entry */ -0.01745 };


You can now “compute” the sine like so, given the argument angle:

answer = sine_table[ angle ];


Because of the duality of arrays and pointers, you can also write this as:

answer = *(sine_table + angle);


Without an optimizing compiler, the second form will probably generate more efficient machine code. In either case, this is very fast because it’s nothing more than reading from a memory location with an offset. The result is just one add plus the access instead of a dozen multiply/adds. It does come at the cost of 360 double floats, which, at eight bytes each, is nearly 3k of memory. By recognizing that the sine function has quarter wave symmetry, you can add a little code to check for the quadrant and reduce the table to just 90 entries. Also, floats might have sufficient precision for the application which will cut the memory requirements in half again when compared to doubles.

To make the above just a little spiffier, you can always make it look like a function via a #define as follows:

#define fast_sin(a)  (*(sine_table+(a)))


Of course, a down side to this operation is that it only deals with an integer argument and is only accurate to a single degree. You can alter the definition to allow a floating point argument and round it to the nearest whole degree as follows:

#define fast_sin(a) (*(sine_table+(int)((a)+0.5)))


You could also turn this into a true function and add code to interpolate between adjacent whole degree entries for a more accurate result. At some point the extra refinements will slow the function to the point where a more direct computation becomes competitive.

1. Outside those bounds you can always perform some minor integer math to get within the bounds (e.g., if the angle is 370, just mod by 360 to get the remainder of 10 degrees, effectively the “wrap around”).