Wanted: fast, low-precision trig functions for C
Leo de Wit
leo at philmds.UUCP
Mon Mar 13 01:08:34 AEST 1989
Sorry for the followup, but my original posting contained an error with
respect to the sin / cos periods. The following one should be ok.
And below is how I would do it (perhaps). sintab[] and costab[] I would
probably generate by a C program, thus avoiding having to do the
initialization. In this case however, init_tab() initiates the sin and
cos tables, using the gonio rules:
sin(a+b) = sin(a) * cos(b) + cos(a) * sin(b);
cos(a+b) = cos(a) * cos(b) - sin(a) * sin(b);
Although these may lead to cumulative errors, these errors are quite small
in respect to the approximations used.
The dsin() and dcos() macros are the simple, table-driven macros, the
macros dsin2() and dcos2() are a first order approximation (the error in
them is typically a factor 100 smaller).
Perhaps dsin2() and dcos2() should better be functions, thus avoiding to
recalculate x % 360.
Be warned! dsin(), dcos, dsin2(), and dcos2() all use their argument
several times, so avoid using side effects or (complex) calculations,
or implement them as functions if you must.
--------- c u t h e r e ----------
#include <math.h>
/* One degree in radians */
#define ONE_DEG (M_PI / 180)
/* sin, cos for pos. x and neg. x (x in degrees), to be used by the macros
* that follow.
*/
#define dsinp(x) sintab[(int)((x) + 0.5) % 360]
#define dsinn(x) -sintab[(int)(-(x) + 0.5) % 360]
#define dcosp(x) costab[(int)((x) + 0.5) % 360]
#define dcosn(x) costab[(int)(-(x) + 0.5) % 360]
/* Zero order approximation: simple table lookup (x in degrees) */
#define dsin(x) (((x) >= 0) ? dsinp(x) : dsinn(x))
#define dcos(x) (((x) >= 0) ? dcosp(x) : dcosn(x))
/* First order approximation (x in degrees) */
#define dsin2(x) (((x) >= 0) \
? (dsinp(x) + ONE_DEG * ((x) - (int)((x) + 0.5)) * dcosp(x)) \
: (dsinn(x) + ONE_DEG * ((x) - (int)((x) - 0.5)) * dcosn(x)))
#define dcos2(x) (((x) >= 0) \
? (dcosp(x) + ONE_DEG * ((x) - (int)((x) + 0.5)) * dsinp(x)) \
: (dcosn(x) - ONE_DEG * ((x) - (int)((x) - 0.5)) * dsinn(x)))
static double sintab[360], costab[360];
static void init_tab(), demo();
main()
{
init_tab();
demo();
}
/* Shows abberation for dsin(), dcos(), dsin2() and dcos2() in the interval
* [-56,-55]
*/
static void demo()
{
double d;
for (d = -55.; d >= -56.; d = d - 0.1) {
printf("%g: %g %g\n", d,sin(d * ONE_DEG) - dsin(d),
cos(d * ONE_DEG) - dcos(d));
printf("%g: %g %g\n", d,sin(d * ONE_DEG) - dsin2(d),
cos(d * ONE_DEG) - dcos2(d));
}
}
/* This builds sintab,costab with errors of size 10^-16, which can
* be ignored without problem (the approximations introduce much
* larger errors).
*/
static void init_tab()
{
int i;
double sin1 = sin(ONE_DEG), cos1 = cos(ONE_DEG);
sintab[0] = sintab[180] = costab[90] = costab[270] = 0.;
costab[0] = sintab[90] = 1.;
costab[180] = sintab[270] = -1.;
for (i = 1; i <= 45; i++) {
sintab[i] = sintab[180 - i]
= costab[90 - i]
= costab[270 + i]
= cos1 * sintab[i - 1] + sin1 * costab[i - 1];
sintab[180 + i] = sintab[360 - i]
= costab[90 + i]
= costab[270 - i]
= -sintab[i];
costab[i] = costab[360 - i]
= sintab[90 + i]
= sintab[90 - i]
= cos1 * costab[i - 1] - sin1 * sintab[i - 1];
costab[180 + i] = costab[180 - i]
= sintab[270 - i]
= sintab[270 + i]
= -costab[i];
}
}
------- e n d s h e r e ----------
Leo.
More information about the Comp.lang.c
mailing list