1 /* Compute sine and cosine of argument.
2    Copyright (C) 2018-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <stdint.h>
21 #include <math.h>
22 #include <math-barriers.h>
23 #include <libm-alias-float.h>
24 #include "math_config.h"
25 #include "s_sincosf.h"
26 
27 #ifndef SINCOSF
28 # define SINCOSF_FUNC __sincosf
29 #else
30 # define SINCOSF_FUNC SINCOSF
31 #endif
32 
33 /* Fast sincosf implementation.  Worst-case ULP is 0.5607, maximum relative
34    error is 0.5303 * 2^-23.  A single-step range reduction is used for
35    small values.  Large inputs have their range reduced using fast integer
36    arithmetic.  */
37 void
SINCOSF_FUNC(float y,float * sinp,float * cosp)38 SINCOSF_FUNC (float y, float *sinp, float *cosp)
39 {
40   double x = y;
41   double s;
42   int n;
43   const sincos_t *p = &__sincosf_table[0];
44 
45   if (abstop12 (y) < abstop12 (pio4))
46     {
47       double x2 = x * x;
48 
49       if (__glibc_unlikely (abstop12 (y) < abstop12 (0x1p-12f)))
50       {
51 	/* Force underflow for tiny y.  */
52 	if (__glibc_unlikely (abstop12 (y) < abstop12 (0x1p-126f)))
53 	  math_force_eval ((float)x2);
54 	*sinp = y;
55 	*cosp = 1.0f;
56 	return;
57       }
58 
59       sincosf_poly (x, x2, p, 0, sinp, cosp);
60     }
61   else if (abstop12 (y) < abstop12 (120.0f))
62     {
63       x = reduce_fast (x, p, &n);
64 
65       /* Setup the signs for sin and cos.  */
66       s = p->sign[n & 3];
67 
68       if (n & 2)
69 	p = &__sincosf_table[1];
70 
71       sincosf_poly (x * s, x * x, p, n, sinp, cosp);
72     }
73   else if (__glibc_likely (abstop12 (y) < abstop12 (INFINITY)))
74     {
75       uint32_t xi = asuint (y);
76       int sign = xi >> 31;
77 
78       x = reduce_large (xi, &n);
79 
80       /* Setup signs for sin and cos - include original sign.  */
81       s = p->sign[(n + sign) & 3];
82 
83       if ((n + sign) & 2)
84 	p = &__sincosf_table[1];
85 
86       sincosf_poly (x * s, x * x, p, n, sinp, cosp);
87     }
88   else
89     {
90       /* Return NaN if Inf or NaN for both sin and cos.  */
91       *sinp = *cosp = y - y;
92 #if WANT_ERRNO
93       /* Needed to set errno for +-Inf, the add is a hack to work
94 	 around a gcc register allocation issue: just passing y
95 	 affects code generation in the fast path (PR86901).  */
96       __math_invalidf (y + y);
97 #endif
98     }
99 }
100 
101 #ifndef SINCOSF
102 libm_alias_float (__sincos, sincos)
103 #endif
104