1//===-- Half-precision cosh(x) function -----------------------------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "src/math/coshf16.h"
10#include "expxf16.h"
11#include "hdr/errno_macros.h"
12#include "hdr/fenv_macros.h"
13#include "src/__support/FPUtil/FEnvImpl.h"
14#include "src/__support/FPUtil/FPBits.h"
15#include "src/__support/FPUtil/except_value_utils.h"
16#include "src/__support/FPUtil/rounding_mode.h"
17#include "src/__support/common.h"
18#include "src/__support/macros/config.h"
19#include "src/__support/macros/optimization.h"
20
21namespace LIBC_NAMESPACE_DECL {
22
23#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
24static constexpr fputil::ExceptValues<float16, 9> COSHF16_EXCEPTS_POS = {{
25 // x = 0x1.6ap-5, coshf16(x) = 0x1p+0 (RZ)
26 {0x29a8U, 0x3c00U, 1U, 0U, 1U},
27 // x = 0x1.8c4p+0, coshf16(x) = 0x1.3a8p+1 (RZ)
28 {0x3e31U, 0x40eaU, 1U, 0U, 0U},
29 // x = 0x1.994p+0, coshf16(x) = 0x1.498p+1 (RZ)
30 {0x3e65U, 0x4126U, 1U, 0U, 0U},
31 // x = 0x1.b6p+0, coshf16(x) = 0x1.6d8p+1 (RZ)
32 {0x3ed8U, 0x41b6U, 1U, 0U, 1U},
33 // x = 0x1.aap+1, coshf16(x) = 0x1.be8p+3 (RZ)
34 {0x42a8U, 0x4afaU, 1U, 0U, 1U},
35 // x = 0x1.cc4p+1, coshf16(x) = 0x1.23cp+4 (RZ)
36 {0x4331U, 0x4c8fU, 1U, 0U, 0U},
37 // x = 0x1.288p+2, coshf16(x) = 0x1.9b4p+5 (RZ)
38 {0x44a2U, 0x526dU, 1U, 0U, 0U},
39 // x = 0x1.958p+2, coshf16(x) = 0x1.1a4p+8 (RZ)
40 {0x4656U, 0x5c69U, 1U, 0U, 0U},
41 // x = 0x1.5fp+3, coshf16(x) = 0x1.c54p+14 (RZ)
42 {0x497cU, 0x7715U, 1U, 0U, 1U},
43}};
44
45static constexpr fputil::ExceptValues<float16, 6> COSHF16_EXCEPTS_NEG = {{
46 // x = -0x1.6ap-5, coshf16(x) = 0x1p+0 (RZ)
47 {0xa9a8U, 0x3c00U, 1U, 0U, 1U},
48 // x = -0x1.b6p+0, coshf16(x) = 0x1.6d8p+1 (RZ)
49 {0xbed8U, 0x41b6U, 1U, 0U, 1U},
50 // x = -0x1.288p+2, coshf16(x) = 0x1.9b4p+5 (RZ)
51 {0xc4a2U, 0x526dU, 1U, 0U, 0U},
52 // x = -0x1.5fp+3, coshf16(x) = 0x1.c54p+14 (RZ)
53 {0xc97cU, 0x7715U, 1U, 0U, 1U},
54 // x = -0x1.8c4p+0, coshf16(x) = 0x1.3a8p+1 (RZ)
55 {0xbe31U, 0x40eaU, 1U, 0U, 0U},
56 // x = -0x1.994p+0, coshf16(x) = 0x1.498p+1 (RZ)
57 {0xbe65U, 0x4126U, 1U, 0U, 0U},
58}};
59#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
60
61LLVM_LIBC_FUNCTION(float16, coshf16, (float16 x)) {
62 using FPBits = fputil::FPBits<float16>;
63 FPBits x_bits(x);
64
65 uint16_t x_u = x_bits.uintval();
66 uint16_t x_abs = x_u & 0x7fffU;
67
68 // When |x| >= acosh(2^16), or x is NaN.
69 if (LIBC_UNLIKELY(x_abs >= 0x49e5U)) {
70 // cosh(NaN) = NaN
71 if (x_bits.is_nan()) {
72 if (x_bits.is_signaling_nan()) {
73 fputil::raise_except_if_required(FE_INVALID);
74 return FPBits::quiet_nan().get_val();
75 }
76
77 return x;
78 }
79
80 // When |x| >= acosh(2^16).
81 if (x_abs >= 0x49e5U) {
82 // cosh(+/-inf) = +inf
83 if (x_bits.is_inf())
84 return FPBits::inf().get_val();
85
86 switch (fputil::quick_get_round()) {
87 case FE_TONEAREST:
88 case FE_UPWARD:
89 fputil::set_errno_if_required(ERANGE);
90 fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
91 return FPBits::inf().get_val();
92 default:
93 return FPBits::max_normal().get_val();
94 }
95 }
96 }
97
98#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
99 if (x_bits.is_pos()) {
100 if (auto r = COSHF16_EXCEPTS_POS.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
101 return r.value();
102 } else {
103 if (auto r = COSHF16_EXCEPTS_NEG.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
104 return r.value();
105 }
106#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
107
108 return eval_sinh_or_cosh</*IsSinh=*/false>(x);
109}
110
111} // namespace LIBC_NAMESPACE_DECL
112

source code of libc/src/math/generic/coshf16.cpp