Home | History | Annotate | Download | only in math
      1 /*
      2  * Single-precision sin/cos function.
      3  *
      4  * Copyright (c) 2018, Arm Limited.
      5  * SPDX-License-Identifier: MIT
      6  */
      7 
      8 #if WANT_SINGLEPREC
      9 #include "single/s_sincosf.c"
     10 #else
     11 
     12 #include <stdint.h>
     13 #include <math.h>
     14 #include "math_config.h"
     15 #include "sincosf.h"
     16 
     17 /* Fast sincosf implementation.  Worst-case ULP is 0.5607, maximum relative
     18    error is 0.5303 * 2^-23.  A single-step range reduction is used for
     19    small values.  Large inputs have their range reduced using fast integer
     20    arithmetic.  */
     21 void
     22 sincosf (float y, float *sinp, float *cosp)
     23 {
     24   double x = y;
     25   double s;
     26   int n;
     27   const sincos_t *p = &__sincosf_table[0];
     28 
     29   if (abstop12 (y) < abstop12 (pio4))
     30     {
     31       double x2 = x * x;
     32 
     33       if (unlikely (abstop12 (y) < abstop12 (0x1p-12f)))
     34 	{
     35 	  if (unlikely (abstop12 (y) < abstop12 (0x1p-126f)))
     36 	    /* Force underflow for tiny y.  */
     37 	    force_eval_float (x2);
     38 	  *sinp = y;
     39 	  *cosp = 1.0f;
     40 	  return;
     41 	}
     42 
     43       sincosf_poly (x, x2, p, 0, sinp, cosp);
     44     }
     45   else if (abstop12 (y) < abstop12 (120.0f))
     46     {
     47       x = reduce_fast (x, p, &n);
     48 
     49       /* Setup the signs for sin and cos.  */
     50       s = p->sign[n & 3];
     51 
     52       if (n & 2)
     53 	p = &__sincosf_table[1];
     54 
     55       sincosf_poly (x * s, x * x, p, n, sinp, cosp);
     56     }
     57   else if (likely (abstop12 (y) < abstop12 (INFINITY)))
     58     {
     59       uint32_t xi = asuint (y);
     60       int sign = xi >> 31;
     61 
     62       x = reduce_large (xi, &n);
     63 
     64       /* Setup signs for sin and cos - include original sign.  */
     65       s = p->sign[(n + sign) & 3];
     66 
     67       if ((n + sign) & 2)
     68 	p = &__sincosf_table[1];
     69 
     70       sincosf_poly (x * s, x * x, p, n, sinp, cosp);
     71     }
     72   else
     73     {
     74       /* Return NaN if Inf or NaN for both sin and cos.  */
     75       *sinp = *cosp = y - y;
     76 #if WANT_ERRNO
     77       /* Needed to set errno for +-Inf, the add is a hack to work
     78 	 around a gcc register allocation issue: just passing y
     79 	 affects code generation in the fast path.  */
     80       __math_invalidf (y + y);
     81 #endif
     82     }
     83 }
     84 
     85 #endif
     86