• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*-
2   * Copyright (c) 2017 Steven G. Kargl
3   * All rights reserved.
4   *
5   * Redistribution and use in source and binary forms, with or without
6   * modification, are permitted provided that the following conditions
7   * are met:
8   * 1. Redistributions of source code must retain the above copyright
9   *    notice unmodified, this list of conditions, and the following
10   *    disclaimer.
11   * 2. Redistributions in binary form must reproduce the above copyright
12   *    notice, this list of conditions and the following disclaimer in the
13   *    documentation and/or other materials provided with the distribution.
14   *
15   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  /**
28   * sinpi(x) computes sin(pi*x) without multiplication by pi (almost).  First,
29   * note that sinpi(-x) = -sinpi(x), so the algorithm considers only |x| and
30   * includes reflection symmetry by considering the sign of x on output.  The
31   * method used depends on the magnitude of x.
32   *
33   * 1. For small |x|, sinpi(x) = pi * x where a sloppy threshold is used.  The
34   *    threshold is |x| < 0x1pN with N = -(P/2+M).  P is the precision of the
35   *    floating-point type and M = 2 to 4.  To achieve high accuracy, pi is
36   *    decomposed into high and low parts with the high part containing a
37   *    number of trailing zero bits.  x is also split into high and low parts.
38   *
39   * 2. For |x| < 1, argument reduction is not required and sinpi(x) is
40   *    computed by calling a kernel that leverages the kernels for sin(x)
41   *    ans cos(x).  See k_sinpi.c and k_cospi.c for details.
42   *
43   * 3. For 1 <= |x| < 0x1p(P-1), argument reduction is required where
44   *    |x| = j0 + r with j0 an integer and the remainder r satisfies
45   *    0 <= r < 1.  With the given domain, a simplified inline floor(x)
46   *    is used.  Also, note the following identity
47   *
48   *    sinpi(x) = sin(pi*(j0+r))
49   *             = sin(pi*j0) * cos(pi*r) + cos(pi*j0) * sin(pi*r)
50   *             = cos(pi*j0) * sin(pi*r)
51   *             = +-sinpi(r)
52   *
53   *    If j0 is even, then cos(pi*j0) = 1. If j0 is odd, then cos(pi*j0) = -1.
54   *    sinpi(r) is then computed via an appropriate kernel.
55   *
56   * 4. For |x| >= 0x1p(P-1), |x| is integral and sinpi(x) = copysign(0,x).
57   *
58   * 5. Special cases:
59   *
60   *    sinpi(+-0) = +-0
61   *    sinpi(+-n) = +-0, for positive integers n.
62   *    sinpi(+-inf) = nan.  Raises the "invalid" floating-point exception.
63   *    sinpi(nan) = nan.  Raises the "invalid" floating-point exception.
64   */
65  
66  #include <float.h>
67  #include "math.h"
68  #include "math_private.h"
69  
70  static const double
71  pi_hi = 3.1415926814079285e+00,	/* 0x400921fb 0x58000000 */
72  pi_lo =-2.7818135228334233e-08;	/* 0xbe5dde97 0x3dcb3b3a */
73  
74  #include "k_cospi.h"
75  #include "k_sinpi.h"
76  
77  volatile static const double vzero = 0;
78  
79  double
sinpi(double x)80  sinpi(double x)
81  {
82  	double ax, hi, lo, s;
83  	uint32_t hx, ix, j0, lx;
84  
85  	EXTRACT_WORDS(hx, lx, x);
86  	ix = hx & 0x7fffffff;
87  	INSERT_WORDS(ax, ix, lx);
88  
89  	if (ix < 0x3ff00000) {			/* |x| < 1 */
90  		if (ix < 0x3fd00000) {		/* |x| < 0.25 */
91  			if (ix < 0x3e200000) {	/* |x| < 0x1p-29 */
92  				if (x == 0)
93  					return (x);
94  				/*
95  				 * To avoid issues with subnormal values,
96  				 * scale the computation and rescale on
97  				 * return.
98  				 */
99  				INSERT_WORDS(hi, hx, 0);
100  				hi *= 0x1p53;
101  				lo = x * 0x1p53 - hi;
102  				s = (pi_lo + pi_hi) * lo + pi_lo * hi +
103  				    pi_hi * hi;
104  				return (s * 0x1p-53);
105  			}
106  
107  			s = __kernel_sinpi(ax);
108  			return ((hx & 0x80000000) ? -s : s);
109  		}
110  
111  		if (ix < 0x3fe00000)		/* |x| < 0.5 */
112  			s = __kernel_cospi(0.5 - ax);
113  		else if (ix < 0x3fe80000)	/* |x| < 0.75 */
114  			s = __kernel_cospi(ax - 0.5);
115  		else
116  			s = __kernel_sinpi(1 - ax);
117  		return ((hx & 0x80000000) ? -s : s);
118  	}
119  
120  	if (ix < 0x43300000) {			/* 1 <= |x| < 0x1p52 */
121  		/* Determine integer part of ax. */
122  		j0 = ((ix >> 20) & 0x7ff) - 0x3ff;
123  		if (j0 < 20) {
124  			ix &= ~(0x000fffff >> j0);
125  			lx = 0;
126  		} else {
127  			lx &= ~((uint32_t)0xffffffff >> (j0 - 20));
128  		}
129  		INSERT_WORDS(x, ix, lx);
130  
131  		ax -= x;
132  		EXTRACT_WORDS(ix, lx, ax);
133  
134  		if (ix == 0)
135  			s = 0;
136  		else {
137  			if (ix < 0x3fe00000) {		/* |x| < 0.5 */
138  				if (ix < 0x3fd00000)	/* |x| < 0.25 */
139  					s = __kernel_sinpi(ax);
140  				else
141  					s = __kernel_cospi(0.5 - ax);
142  			} else {
143  				if (ix < 0x3fe80000)	/* |x| < 0.75 */
144  					s = __kernel_cospi(ax - 0.5);
145  				else
146  					s = __kernel_sinpi(1 - ax);
147  			}
148  
149  			if (j0 > 30)
150  				x -= 0x1p30;
151  			j0 = (uint32_t)x;
152  			if (j0 & 1) s = -s;
153  		}
154  
155  		return ((hx & 0x80000000) ? -s : s);
156  	}
157  
158  	if (ix >= 0x7f800000)
159  		return (vzero / vzero);
160  
161  	/*
162  	 * |x| >= 0x1p52 is always an integer, so return +-0.
163  	 */
164  	return (copysign(0, x));
165  }
166  
167  #if LDBL_MANT_DIG == 53
168  __weak_reference(sinpi, sinpil);
169  #endif
170