brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.2 KiB · 50c9a8f Raw
107 lines · c
1//===-- Implementation header for cosf16 ------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_COSF16_H10#define LLVM_LIBC_SRC___SUPPORT_MATH_COSF16_H11 12#include "include/llvm-libc-macros/float16-macros.h"13 14#ifdef LIBC_TYPES_HAS_FLOAT1615 16#include "sincosf16_utils.h"17#include "src/__support/FPUtil/FEnvImpl.h"18#include "src/__support/FPUtil/FPBits.h"19#include "src/__support/FPUtil/cast.h"20#include "src/__support/FPUtil/except_value_utils.h"21#include "src/__support/FPUtil/multiply_add.h"22#include "src/__support/macros/optimization.h"23 24namespace LIBC_NAMESPACE_DECL {25 26namespace math {27 28LIBC_INLINE static constexpr float16 cosf16(float16 x) {29#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS30  constexpr size_t N_EXCEPTS = 4;31 32  constexpr fputil::ExceptValues<float16, N_EXCEPTS> COSF16_EXCEPTS{{33      // (input, RZ output, RU offset, RD offset, RN offset)34      {0x2b7c, 0x3bfc, 1, 0, 1},35      {0x4ac1, 0x38b5, 1, 0, 0},36      {0x5c49, 0xb8c6, 0, 1, 0},37      {0x7acc, 0xa474, 0, 1, 0},38  }};39#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS40 41  using namespace sincosf16_internal;42  using FPBits = fputil::FPBits<float16>;43  FPBits xbits(x);44 45  uint16_t x_u = xbits.uintval();46  uint16_t x_abs = x_u & 0x7fff;47  float xf = x;48 49  // Range reduction:50  // For |x| > pi/32, we perform range reduction as follows:51  // Find k and y such that:52  //   x = (k + y) * pi/3253  //   k is an integer, |y| < 0.554  //55  // This is done by performing:56  //   k = round(x * 32/pi)57  //   y = x * 32/pi - k58  //59  // Once k and y are computed, we then deduce the answer by the cosine of sum60  // formula:61  //   cos(x) = cos((k + y) * pi/32)62  //          = cos(k * pi/32) * cos(y * pi/32) -63  //            sin(k * pi/32) * sin(y * pi/32)64 65#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS66  // Handle exceptional values67  if (auto r = COSF16_EXCEPTS.lookup(x_abs); LIBC_UNLIKELY(r.has_value()))68    return r.value();69#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS70 71  // cos(+/-0) = 172  if (LIBC_UNLIKELY(x_abs == 0U))73    return fputil::cast<float16>(1.0f);74 75  // cos(+/-inf) = NaN, and cos(NaN) = NaN76  if (xbits.is_inf_or_nan()) {77    if (xbits.is_signaling_nan()) {78      fputil::raise_except_if_required(FE_INVALID);79      return FPBits::quiet_nan().get_val();80    }81 82    if (xbits.is_inf()) {83      fputil::set_errno_if_required(EDOM);84      fputil::raise_except_if_required(FE_INVALID);85    }86 87    return x + FPBits::quiet_nan().get_val();88  }89 90  float sin_k = 0.0f, cos_k = 0.0f, sin_y = 0.0f, cosm1_y = 0.0f;91  sincosf16_eval(xf, sin_k, cos_k, sin_y, cosm1_y);92  // Since, cosm1_y = cos_y - 1, therefore:93  //   cos(x) = cos_k * cos_y - sin_k * sin_y94  //          = cos_k * (cos_y - 1 + 1) - sin_k * sin_y95  //          = cos_k * cosm1_y - sin_k * sin_y + cos_k96  return fputil::cast<float16>(fputil::multiply_add(97      cos_k, cosm1_y, fputil::multiply_add(-sin_k, sin_y, cos_k)));98}99 100} // namespace math101 102} // namespace LIBC_NAMESPACE_DECL103 104#endif // LIBC_TYPES_HAS_FLOAT16105 106#endif // LLVM_LIBC_SRC___SUPPORT_MATH_COSF16_H107