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.