/* Listing 3. */
typedef struct {
    float cos1, sin1, cos2, sin2;
}      ARG_FF_2;		/* vector 4 pairs */
ARG_FF_2 cosf_sinf_2(x1, x2)
    union {
	float flt;
	int iflt;
    }     x1, x2;
{				/* 2 pair single precision
				   sin/cos function */
#include "float.h"
#if FLT_ROUNDS != 1
	#error "rounding mode not nearest, fix code"
#endif
#include <errno.h>
#ifndef errno
    extern int errno;
#endif
#include <math.h>
#define M_2_PI		0.63661977236758134308
#define T2PI		2*M_2_PI
#define TP2		T2PI*T2PI
#define TP3		TP2*T2PI
#define TP4		TP2*TP2
#define TP5		TP3*TP2
    ARG_FF_2 res;
    double tn, td, r;
/* integer compare with 0 same as float, for IEEE
** since arg comes in int register, this is faster
**
** doing everything in double, we won't lose accuracy
** by converting arg to multiple of PI/2
** this allows range reduction by subtracting an integer
**
** reduce to range +- 2, divide by 2 later
** when it cannot underflow */
    tn = x1.flt * M_2_PI + (td = x1.iflt >= 0 ?
		    4 / LDBL_EPSILON : -4 / LDBL_EPSILON);
    if (fabs(x1.flt * M_2_PI) >= 4 / LDBL_EPSILON |
	fabs(x2.flt * M_2_PI) >= 4 / LDBL_EPSILON)
	errno = ERANGE;
    tn -= td;
    tn = x1.flt * M_2_PI - tn;
    td = tn * tn;
/* divide arg by 2 and rationalize numerator and denominator
** numerator of rational approx for tan(x1/2)
** Horner polynomials 1st time */
    tn *= 886.77348 * TP4 + td * (-99.398954 * TP2 + td);
/* denominator */
    td = 886.77346 * TP5 + td *
	(-394.98971 * TP3 + td * 14.425694 * T2PI);
/* cos, sin half angle formulae, rationalized */
    res.cos1 = (td * td - tn * tn) / (td * td + tn * tn);
    res.sin1 = (tn * td + tn * td) / (td * td + tn * tn);
/* copy 2 */
    tn = x2.flt * M_2_PI + (td = x2.iflt >= 0 ?
		    4 / LDBL_EPSILON : -4 / LDBL_EPSILON);
    tn -= td;
    tn = x2.flt * M_2_PI - tn;
    td = tn * tn;
/* distribute terms to finish polynomials quicker */
    tn *= 886.77348 * TP4 - td * 99.398954 * TP2 + td * td;
    r = 886.77346 * TP5 - td * 394.98971 * TP3;
    td = r + td * td * 14.425694 * T2PI;
    res.cos2 = (td * td - tn * tn) / (td * td + tn * tn);
    res.sin2 = (tn * td + tn * td) / (td * td + tn * tn);
    return res;
}
