1/*
2 * Single-precision cos function.
3 *
4 * Copyright (c) 2018-2021, Arm Limited.
5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6 */
7
8#include <stdint.h>
9#include <math.h>
10#include "math_config.h"
11#include "sincosf.h"
12
13/* Fast cosf implementation.  Worst-case ULP is 0.5607, maximum relative
14   error is 0.5303 * 2^-23.  A single-step range reduction is used for
15   small values.  Large inputs have their range reduced using fast integer
16   arithmetic.  */
17float
18cosf (float y)
19{
20  double x = y;
21  double s;
22  int n;
23  const sincos_t *p = &__sincosf_table[0];
24
25  if (abstop12 (y) < abstop12 (pio4f))
26    {
27      double x2 = x * x;
28
29      if (unlikely (abstop12 (y) < abstop12 (0x1p-12f)))
30	return 1.0f;
31
32      return sinf_poly (x, x2, p, 1);
33    }
34  else if (likely (abstop12 (y) < abstop12 (120.0f)))
35    {
36      x = reduce_fast (x, p, &n);
37
38      /* Setup the signs for sin and cos.  */
39      s = p->sign[n & 3];
40
41      if (n & 2)
42	p = &__sincosf_table[1];
43
44      return sinf_poly (x * s, x * x, p, n ^ 1);
45    }
46  else if (abstop12 (y) < abstop12 (INFINITY))
47    {
48      uint32_t xi = asuint (y);
49      int sign = xi >> 31;
50
51      x = reduce_large (xi, &n);
52
53      /* Setup signs for sin and cos - include original sign.  */
54      s = p->sign[(n + sign) & 3];
55
56      if ((n + sign) & 2)
57	p = &__sincosf_table[1];
58
59      return sinf_poly (x * s, x * x, p, n ^ 1);
60    }
61  else
62    return __math_invalidf (y);
63}
64