summaryrefslogtreecommitdiff
path: root/usr/src/libm/src/C/__rem_pio2.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/libm/src/C/__rem_pio2.c')
-rw-r--r--usr/src/libm/src/C/__rem_pio2.c167
1 files changed, 167 insertions, 0 deletions
diff --git a/usr/src/libm/src/C/__rem_pio2.c b/usr/src/libm/src/C/__rem_pio2.c
new file mode 100644
index 0000000..2862e74
--- /dev/null
+++ b/usr/src/libm/src/C/__rem_pio2.c
@@ -0,0 +1,167 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "@(#)__rem_pio2.c 1.13 06/01/23 SMI"
+
+/*
+ * __rem_pio2(x, y) passes back a better-than-double-precision
+ * approximation to x mod pi/2 in y[0]+y[1] and returns an integer
+ * congruent mod 8 to the integer part of x/(pi/2).
+ *
+ * This implementation tacitly assumes that x is finite and at
+ * least about pi/4 in magnitude.
+ */
+
+#include "libm.h"
+
+extern const int _TBL_ipio2_inf[];
+
+/* INDENT OFF */
+/*
+ * invpio2: 53 bits of 2/pi
+ * pio2_1: first 33 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ * pio2_2: second 33 bit of pi/2
+ * pio2_2t: pi/2 - pio2_2
+ * pio2_3: third 33 bit of pi/2
+ * pio2_3t: pi/2 - pio2_3
+ */
+static const double
+ half = 0.5,
+ invpio2 = 0.636619772367581343075535, /* 2^ -1 * 1.45F306DC9C883 */
+ pio2_1 = 1.570796326734125614166, /* 2^ 0 * 1.921FB54400000 */
+ pio2_1t = 6.077100506506192601475e-11, /* 2^-34 * 1.0B4611A626331 */
+ pio2_2 = 6.077100506303965976596e-11, /* 2^-34 * 1.0B4611A600000 */
+ pio2_2t = 2.022266248795950732400e-21, /* 2^-69 * 1.3198A2E037073 */
+ pio2_3 = 2.022266248711166455796e-21, /* 2^-69 * 1.3198A2E000000 */
+ pio2_3t = 8.478427660368899643959e-32; /* 2^-104 * 1.B839A252049C1 */
+/* INDENT ON */
+
+int
+__rem_pio2(double x, double *y) {
+ double w, t, r, fn;
+ double tx[3];
+ int e0, i, j, nx, n, ix, hx, lx;
+
+ hx = ((int *)&x)[HIWORD];
+ ix = hx & 0x7fffffff;
+
+ if (ix < 0x4002d97c) {
+ /* |x| < 3pi/4, special case with n=1 */
+ t = fabs(x) - pio2_1;
+ if (ix != 0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = t - pio2_1t;
+ y[1] = (t - y[0]) - pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ t -= pio2_2;
+ y[0] = t - pio2_2t;
+ y[1] = (t - y[0]) - pio2_2t;
+ }
+ if (hx < 0) {
+ y[0] = -y[0];
+ y[1] = -y[1];
+ return (-1);
+ }
+ return (1);
+ }
+
+ if (ix <= 0x413921fb) {
+ /* |x| <= 2^19 pi */
+ t = fabs(x);
+ n = (int)(t * invpio2 + half);
+ fn = (double)n;
+ r = t - fn * pio2_1;
+ j = ix >> 20;
+ w = fn * pio2_1t; /* 1st round good to 85 bit */
+ y[0] = r - w;
+ i = j - ((((int *)y)[HIWORD] >> 20) & 0x7ff);
+ if (i > 16) { /* 2nd iteration (rare) */
+ /* 2nd round good to 118 bit */
+ if (i < 35) {
+ t = r; /* r-fn*pio2_2 may not be exact */
+ w = fn * pio2_2;
+ r = t - w;
+ w = fn * pio2_2t - ((t - r) - w);
+ y[0] = r - w;
+ } else {
+ r -= fn * pio2_2;
+ w = fn * pio2_2t;
+ y[0] = r - w;
+ i = j - ((((int *)y)[HIWORD] >> 20) & 0x7ff);
+ if (i > 49) {
+ /* 3rd iteration (extremely rare) */
+ if (i < 68) {
+ t = r;
+ w = fn * pio2_3;
+ r = t - w;
+ w = fn * pio2_3t -
+ ((t - r) - w);
+ y[0] = r - w;
+ } else {
+ /*
+ * 3rd round good to 151 bits;
+ * covered all possible cases
+ */
+ r -= fn * pio2_3;
+ w = fn * pio2_3t;
+ y[0] = r - w;
+ }
+ }
+ }
+ }
+ y[1] = (r - y[0]) - w;
+ if (hx < 0) {
+ y[0] = -y[0];
+ y[1] = -y[1];
+ return (-n);
+ }
+ return (n);
+ }
+
+ e0 = (ix >> 20) - 1046; /* e0 = ilogb(x)-23; */
+
+ /* break x into three 24 bit pieces */
+ lx = ((int *)&x)[LOWORD];
+ i = (lx & 0x1f) << 19;
+ tx[2] = (double)i;
+ j = (lx >> 5) & 0xffffff;
+ tx[1] = (double)j;
+ tx[0] = (double)((((ix & 0xfffff) | 0x100000) << 3) |
+ ((unsigned)lx >> 29));
+ nx = 3;
+ if (i == 0) {
+ /* skip zero term */
+ nx--;
+ if (j == 0)
+ nx--;
+ }
+ n = __rem_pio2m(tx, y, e0, nx, 2, _TBL_ipio2_inf);
+ if (hx < 0) {
+ y[0] = -y[0];
+ y[1] = -y[1];
+ return (-n);
+ }
+ return (n);
+}