The following article was printed in April 1979 of the magazine „BYTE".
This article demonstrates computation of reals using integers, here implemented on a MOTOROLA 6800 CPU
An article calculating sine, cosine, square and square root functions using integer maths will be found here. One more article calculating sine, cosine functions using integer maths will be found here. Another article computes square roots.

An Easy Way to Calculate Sines and Cosines

Robert Grappel
148 Wood St
Lexington MA 02173

The instruction set of a typical 8 bit processor can be quite confining at times. Any task requiring more than simple integer addition and subtraction can become a nuisance. There are reference books from which multiplication and division routines can be obtained, and square root and other functions can be built by using expansion, iteration, or other well-known methods. Implementing these algorithms on a microprocessor uses much space and programming time. Trigonometric functions are among this class of difficult functions. However, if one can tolerate accuracy of one part in 100, and allow about 1 ms per computation, the routine described in this article will provide sine and cosine values in a very simple 40 byte routine. I have coded it for a Motorola M6800 processor but it could easily be converted to any other processor.

Theory

The algorithm is based on two trigonometric identities:

sine(Θ+s) = sin(Θ)cos(s) + cos(Θ)sin(s)
cos(Θ+s) = cos(Θ)cos(s) - sin(Θ)sin(s)

where Θ is the angle we are interested in and s is a small step in angle added to Θ. If we make the step small enough, we can approximate sin(s) and cos(s) as follows:

sin(s) = s
cos(s) = 1

Combining these four equations we get:

sine(Θ+s) = sin(Θ) + s cos(Θ)
cos(Θ+s) = cos(Θ) - s sin(Θ)

Solving for sine and substituting into the cosine formula:

cos(Θ+s) = (1+s²)cos(Θ) - s sin(Θ+s)

Since s is very small, we can neglect s² and write:

cos(Θ+s) = cos(Θ) - s sin(Θ+s)

Given that we have values for sin(Θ) and cos(Θ) at some point, we can get to any other angle by stepping through the two approximations, first computing sin(Θ+s) and then using that to compute cos(Θ+s). We choose to start at Θ equal to zero, and set cos(Θ) to the largest positive value that can be stored as a signed byte without causing overflow when negated and decremented. Hence cos(0) = 126. Similarly the sin(0) = 0. The step size is chosen to be 0.0625 radian or about 3.58°. The step size must be a binary fraction so that all the multiplication involved in the equations can be performed by arithmetic shifts. If more accuracy is needed, the step size is easily reduced by introducing more shifts into the algorithm.

Program

The assembly code program for the Motorola 6800 version of the routine is shown in listing 1.

          Op
Location Code  Operand  Label             Assembly  Code
                        * SUBROUTINE TO COMPUTE SINE AND COSINE
                        * AS SINGLE-BYTE INTEGERS (SIGNED)
                        * STEP SIZE OF 1/16 RADIAN, OR 3.58 DEGREES
                        * ACCURACY OF ABOUT 1% FOR RANGE 0
                            THROUGH 90 DEGREES
                        *
  0000                  THETA  RMB 1 *ARGUMENT TO FUNCTION
  0001                  SINE   RMB 1 *SINE OF THETA
  0002                  COSINE RMB 1 *COSINE OF THETA
  0003    86    7E      START  LDA A #126 *BEGIN INITIALIZATION
  0005    B7    0002           STA A COSINE
  0008    7F    0001           CLR SINE
  000B    B6    0000           LDA A THETA
  000E    F6    0002           LDA B COSINE *COMPUTE NEW SINE
  0011    57            CYCLE  ASR B
  0012    57                   ASR B
  0013    57                   ASR B
  0014    57                   ASR B
  0015    FB    0001           ADD B SINE
  0018    F7    0001           STA B SINE
  001B    57                   ASR B *COMPUTE NEW COSINE
  001C    57                   ASR B
  001D    57                   ASR B
  001E    57                   ASR B
  001F    F0    0002           SUB B COSINE
  0022    50                   NEG B
  0023    F7    0002           STA B COSINE
  0026    4A                   DEC A
  0027    2C E8                BGE CYCLE *LOOP UNTIL DONE
  0029    39                   RTS
Listing 1: 6800 routine for computing sines and cosines over the range 0 to π/2 radians (0 to 90 degrees).
[Listing for Z80 CPU]

When called with the angle stored in variable THETA, it returns the sine and cosine of that angle. The accuracy Is quite good for angles less than π/2 radians (90 degrees). For angles larger than π/2 radians, other trigonometric identities can be used:

sine(Θ) = cos(π/2-Θ) = sin(π-Θ)
cos(Θ) = sin(π/2-Θ) = (-cos(π-Θ))

Thus, the sine and cosine of any angle can be computed from the values over the range 0 to π/2 radians. These identities can be coded quite easily.
All the other trigonometric functions can be computed from the values of sine and cosine. All that is needed is an integer division routine such as the following:

cosec(Θ) = 126/sin(Θ)
sec(Θ) = 126/cos(Θ)
tan(Θ) = sin(Θ)/cos(Θ)
cot(Θ) = cos(Θ)/sin(Θ)

Be careful of overflows and division by zero problems.
This algorithm can perform other tricks. It can generate continuous sine waves of any desired amplitude, period, or phase. Coupled with a digital to analog converter, it could form part of a modem or synthesizer. It could simulate mixers, AM or FM modulators, keyers, etc.
The maximum frequency it can generate depends on the processor cycle time. A 6800 processor running with a 1 MHz clock could generate a 200 Hz sine wave since there are about 50 machine cycles per step, and about 100 steps per wave. Increasing the step size to 0.125 radians would increase the maximum frequency to about 500 Hz. A step size of 0.25 radians would yield a maximum frequency of nearly 1050 Hz.
I hope that this algorithm will help programmers solve problems involving trigonometric functions, and that applications for microcomputers will expand into new areas where these functions are useful.

Scanned by Werner Cirsovius
January 2014
© BYTE Publications Inc.