xref: /openbsd/lib/libm/src/s_sincosl.c (revision 65a55a55)
16c640833Skettenis /*-
26c640833Skettenis  * Copyright (c) 2007, 2010-2013 Steven G. Kargl
36c640833Skettenis  * All rights reserved.
46c640833Skettenis  *
56c640833Skettenis  * Redistribution and use in source and binary forms, with or without
66c640833Skettenis  * modification, are permitted provided that the following conditions
76c640833Skettenis  * are met:
86c640833Skettenis  * 1. Redistributions of source code must retain the above copyright
96c640833Skettenis  *    notice unmodified, this list of conditions, and the following
106c640833Skettenis  *    disclaimer.
116c640833Skettenis  * 2. Redistributions in binary form must reproduce the above copyright
126c640833Skettenis  *    notice, this list of conditions and the following disclaimer in the
136c640833Skettenis  *    documentation and/or other materials provided with the distribution.
146c640833Skettenis  *
156c640833Skettenis  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
166c640833Skettenis  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
176c640833Skettenis  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
186c640833Skettenis  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
196c640833Skettenis  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
206c640833Skettenis  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
216c640833Skettenis  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
226c640833Skettenis  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
236c640833Skettenis  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
246c640833Skettenis  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
256c640833Skettenis  *
266c640833Skettenis  * s_sinl.c and s_cosl.c merged by Steven G. Kargl.
276c640833Skettenis  */
286c640833Skettenis 
296c640833Skettenis #include <sys/types.h>
306c640833Skettenis #include <machine/ieee.h>
316c640833Skettenis #include <float.h>
326c640833Skettenis #include <math.h>
336c640833Skettenis 
346c640833Skettenis #include "math_private.h"
356c640833Skettenis 
366c640833Skettenis #if LDBL_MANT_DIG == 64
376c640833Skettenis #include "../ld80/k_sincosl.h"
386c640833Skettenis #define	NX	3
396c640833Skettenis #define	PREC	2
406c640833Skettenis #elif LDBL_MANT_DIG == 113
416c640833Skettenis #include "../ld128/k_sincosl.h"
426c640833Skettenis #define	NX	5
436c640833Skettenis #define	PREC	3
446c640833Skettenis #else
456c640833Skettenis #error "Unsupported long double format"
466c640833Skettenis #endif
476c640833Skettenis 
486c640833Skettenis static const long double two24 = 1.67772160000000000000e+07L;
496c640833Skettenis 
506c640833Skettenis void
sincosl(long double x,long double * sn,long double * cs)516c640833Skettenis sincosl(long double x, long double *sn, long double *cs)
526c640833Skettenis {
536c640833Skettenis 	union {
546c640833Skettenis 		long double e;
556c640833Skettenis 		struct ieee_ext bits;
566c640833Skettenis 	} z;
576c640833Skettenis 	int i, e0;
586c640833Skettenis 	double xd[NX], yd[PREC];
596c640833Skettenis 	long double hi, lo;
606c640833Skettenis 
616c640833Skettenis 	z.e = x;
626c640833Skettenis 	z.bits.ext_sign = 0;
636c640833Skettenis 
646c640833Skettenis 	/* Optimize the case where x is already within range. */
656c640833Skettenis 	if (z.e < M_PI_4) {
666c640833Skettenis 		/*
676c640833Skettenis 		 * If x = +-0 or x is a subnormal number, then sin(x) = x and
686c640833Skettenis 		 * cos(x) = 1.
696c640833Skettenis 		 */
706c640833Skettenis 		if (z.bits.ext_exp == 0) {
716c640833Skettenis 			*sn = x;
726c640833Skettenis 			*cs = 1;
736c640833Skettenis 		} else
746c640833Skettenis 			__kernel_sincosl(x, 0, 0, sn, cs);
75*65a55a55Sjsg 		return;
766c640833Skettenis 	}
776c640833Skettenis 
786c640833Skettenis 	/* If x = NaN or Inf, then sin(x) and cos(x) are NaN. */
796c640833Skettenis 	if (z.bits.ext_exp == 32767) {
806c640833Skettenis 		*sn = x - x;
816c640833Skettenis 		*cs = x - x;
82*65a55a55Sjsg 		return;
836c640833Skettenis 	}
846c640833Skettenis 
856c640833Skettenis 	/* Split z.e into a 24-bit representation. */
866c640833Skettenis 	e0 = ilogbl(z.e) - 23;
876c640833Skettenis 	z.e = scalbnl(z.e, -e0);
886c640833Skettenis 	for (i = 0; i < NX; i++) {
896c640833Skettenis 		xd[i] = (double)((int32_t)z.e);
906c640833Skettenis 		z.e = (z.e - xd[i]) * two24;
916c640833Skettenis 	}
926c640833Skettenis 
936c640833Skettenis 	/* yd contains the pieces of xd rem pi/2 such that |yd| < pi/4. */
946c640833Skettenis 	e0 = __kernel_rem_pio2(xd, yd, e0, NX, PREC);
956c640833Skettenis 
966c640833Skettenis #if PREC == 2
976c640833Skettenis 	hi = (long double)yd[0] + yd[1];
986c640833Skettenis 	lo = yd[1] - (hi - yd[0]);
996c640833Skettenis #else /* PREC == 3 */
1006c640833Skettenis 	long double t;
1016c640833Skettenis 	t = (long double)yd[2] + yd[1];
1026c640833Skettenis 	hi = t + yd[0];
1036c640833Skettenis 	lo = yd[0] - (hi - t);
1046c640833Skettenis #endif
1056c640833Skettenis 
1066c640833Skettenis 	switch (e0 & 3) {
1076c640833Skettenis 	case 0:
1086c640833Skettenis 		__kernel_sincosl(hi, lo, 1, sn, cs);
1096c640833Skettenis 		break;
1106c640833Skettenis 	case 1:
1116c640833Skettenis 		__kernel_sincosl(hi, lo, 1, cs, sn);
1126c640833Skettenis 		*cs = -*cs;
1136c640833Skettenis 		break;
1146c640833Skettenis 	case 2:
1156c640833Skettenis 		__kernel_sincosl(hi, lo, 1, sn, cs);
1166c640833Skettenis 		*sn = -*sn;
1176c640833Skettenis 		*cs = -*cs;
1186c640833Skettenis 		break;
1196c640833Skettenis 	default:
1206c640833Skettenis 		__kernel_sincosl(hi, lo, 1, cs, sn);
1216c640833Skettenis 		*sn = -*sn;
1226c640833Skettenis 	}
1236c640833Skettenis }
124