master
  1/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */
  2/*
  3 * ====================================================
  4 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  5 *
  6 * Developed at SunSoft, a Sun Microsystems, Inc. business.
  7 * Permission to use, copy, modify, and distribute this
  8 * software is freely granted, provided that this notice
  9 * is preserved.
 10 * ====================================================
 11 *
 12 * Optimized by Bruce D. Evans.
 13 */
 14/* __rem_pio2(x,y)
 15 *
 16 * return the remainder of x rem pi/2 in y[0]+y[1]
 17 * use __rem_pio2_large() for large x
 18 */
 19
 20#include "libm.h"
 21
 22#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
 23#define EPS DBL_EPSILON
 24#elif FLT_EVAL_METHOD==2
 25#define EPS LDBL_EPSILON
 26#endif
 27
 28/*
 29 * invpio2:  53 bits of 2/pi
 30 * pio2_1:   first  33 bit of pi/2
 31 * pio2_1t:  pi/2 - pio2_1
 32 * pio2_2:   second 33 bit of pi/2
 33 * pio2_2t:  pi/2 - (pio2_1+pio2_2)
 34 * pio2_3:   third  33 bit of pi/2
 35 * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
 36 */
 37static const double
 38toint   = 1.5/EPS,
 39#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes
 40pio4    = 0x1.921fb54442d18p-1,
 41#endif
 42invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
 43pio2_1  = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
 44pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
 45pio2_2  = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
 46pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
 47pio2_3  = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
 48pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
 49
 50/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
 51int __rem_pio2(double x, double *y)
 52{
 53	union {double f; uint64_t i;} u = {x};
 54	double_t z,w,t,r,fn;
 55	double tx[3],ty[2];
 56	uint32_t ix;
 57	int sign, n, ex, ey, i;
 58
 59	sign = u.i>>63;
 60	ix = u.i>>32 & 0x7fffffff;
 61	if (ix <= 0x400f6a7a) {  /* |x| ~<= 5pi/4 */
 62		if ((ix & 0xfffff) == 0x921fb)  /* |x| ~= pi/2 or 2pi/2 */
 63			goto medium;  /* cancellation -- use medium case */
 64		if (ix <= 0x4002d97c) {  /* |x| ~<= 3pi/4 */
 65			if (!sign) {
 66				z = x - pio2_1;  /* one round good to 85 bits */
 67				y[0] = z - pio2_1t;
 68				y[1] = (z-y[0]) - pio2_1t;
 69				return 1;
 70			} else {
 71				z = x + pio2_1;
 72				y[0] = z + pio2_1t;
 73				y[1] = (z-y[0]) + pio2_1t;
 74				return -1;
 75			}
 76		} else {
 77			if (!sign) {
 78				z = x - 2*pio2_1;
 79				y[0] = z - 2*pio2_1t;
 80				y[1] = (z-y[0]) - 2*pio2_1t;
 81				return 2;
 82			} else {
 83				z = x + 2*pio2_1;
 84				y[0] = z + 2*pio2_1t;
 85				y[1] = (z-y[0]) + 2*pio2_1t;
 86				return -2;
 87			}
 88		}
 89	}
 90	if (ix <= 0x401c463b) {  /* |x| ~<= 9pi/4 */
 91		if (ix <= 0x4015fdbc) {  /* |x| ~<= 7pi/4 */
 92			if (ix == 0x4012d97c)  /* |x| ~= 3pi/2 */
 93				goto medium;
 94			if (!sign) {
 95				z = x - 3*pio2_1;
 96				y[0] = z - 3*pio2_1t;
 97				y[1] = (z-y[0]) - 3*pio2_1t;
 98				return 3;
 99			} else {
100				z = x + 3*pio2_1;
101				y[0] = z + 3*pio2_1t;
102				y[1] = (z-y[0]) + 3*pio2_1t;
103				return -3;
104			}
105		} else {
106			if (ix == 0x401921fb)  /* |x| ~= 4pi/2 */
107				goto medium;
108			if (!sign) {
109				z = x - 4*pio2_1;
110				y[0] = z - 4*pio2_1t;
111				y[1] = (z-y[0]) - 4*pio2_1t;
112				return 4;
113			} else {
114				z = x + 4*pio2_1;
115				y[0] = z + 4*pio2_1t;
116				y[1] = (z-y[0]) + 4*pio2_1t;
117				return -4;
118			}
119		}
120	}
121	if (ix < 0x413921fb) {  /* |x| ~< 2^20*(pi/2), medium size */
122medium:
123		/* rint(x/(pi/2)) */
124		fn = (double_t)x*invpio2 + toint - toint;
125		n = (int32_t)fn;
126		r = x - fn*pio2_1;
127		w = fn*pio2_1t;  /* 1st round, good to 85 bits */
128#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes
129		/* Matters with directed rounding. */
130		if (predict_false(r - w < -pio4)) {
131			n--;
132			fn--;
133			r = x - fn*pio2_1;
134			w = fn*pio2_1t;
135		} else if (predict_false(r - w > pio4)) {
136			n++;
137			fn++;
138			r = x - fn*pio2_1;
139			w = fn*pio2_1t;
140		}
141#endif
142		y[0] = r - w;
143		u.f = y[0];
144		ey = u.i>>52 & 0x7ff;
145		ex = ix>>20;
146		if (ex - ey > 16) { /* 2nd round, good to 118 bits */
147			t = r;
148			w = fn*pio2_2;
149			r = t - w;
150			w = fn*pio2_2t - ((t-r)-w);
151			y[0] = r - w;
152			u.f = y[0];
153			ey = u.i>>52 & 0x7ff;
154			if (ex - ey > 49) {  /* 3rd round, good to 151 bits, covers all cases */
155				t = r;
156				w = fn*pio2_3;
157				r = t - w;
158				w = fn*pio2_3t - ((t-r)-w);
159				y[0] = r - w;
160			}
161		}
162		y[1] = (r - y[0]) - w;
163		return n;
164	}
165	/*
166	 * all other (large) arguments
167	 */
168	if (ix >= 0x7ff00000) {  /* x is inf or NaN */
169		y[0] = y[1] = x - x;
170		return 0;
171	}
172	/* set z = scalbn(|x|,-ilogb(x)+23) */
173	u.f = x;
174	u.i &= (uint64_t)-1>>12;
175	u.i |= (uint64_t)(0x3ff + 23)<<52;
176	z = u.f;
177	for (i=0; i < 2; i++) {
178		tx[i] = (double)(int32_t)z;
179		z     = (z-tx[i])*0x1p24;
180	}
181	tx[i] = z;
182	/* skip zero terms, first term is non-zero */
183	while (tx[i] == 0.0)
184		i--;
185	n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1);
186	if (sign) {
187		y[0] = -ty[0];
188		y[1] = -ty[1];
189		return -n;
190	}
191	y[0] = ty[0];
192	y[1] = ty[1];
193	return n;
194}