Skip to content

Commit fcb9d7e

Browse files
author
Kirill Okhotnikov
committed
[libc][math] Added coshf function.
Differential Revision: https://reviews.llvm.org/D129275
1 parent a8b726a commit fcb9d7e

File tree

16 files changed

+276
-2
lines changed

16 files changed

+276
-2
lines changed

libc/config/darwin/arm/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ set(TARGET_LIBM_ENTRYPOINTS
111111
libc.src.math.ceil
112112
libc.src.math.ceilf
113113
libc.src.math.ceill
114+
libc.src.math.coshf
114115
libc.src.math.cosf
115116
libc.src.math.expf
116117
libc.src.math.exp2f

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ set(TARGET_LIBM_ENTRYPOINTS
130130
libc.src.math.ceil
131131
libc.src.math.ceilf
132132
libc.src.math.ceill
133+
libc.src.math.coshf
133134
libc.src.math.cosf
134135
libc.src.math.expf
135136
libc.src.math.exp2f

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ set(TARGET_LIBM_ENTRYPOINTS
136136
libc.src.math.ceilf
137137
libc.src.math.ceill
138138
libc.src.math.cos
139+
libc.src.math.coshf
139140
libc.src.math.cosf
140141
libc.src.math.expf
141142
libc.src.math.exp2f

libc/config/windows/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ set(TARGET_LIBM_ENTRYPOINTS
114114
libc.src.math.ceill
115115
libc.src.math.cos
116116
libc.src.math.cosf
117+
libc.src.math.coshf
117118
libc.src.math.expf
118119
libc.src.math.exp2f
119120
libc.src.math.expm1f

libc/spec/stdc.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@ def StdC : StandardSpec<"stdc"> {
470470
FunctionSpec<"nextafterf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
471471
FunctionSpec<"nextafter", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
472472
FunctionSpec<"nextafterl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
473+
474+
FunctionSpec<"coshf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
473475
]
474476
>;
475477

libc/src/__support/FPUtil/FPBits.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ template <typename T> struct FPBits {
153153

154154
static constexpr FPBits<T> neg_zero() { return zero(true); }
155155

156-
static constexpr FPBits<T> inf() {
157-
FPBits<T> bits;
156+
static constexpr FPBits<T> inf(bool sign = false) {
157+
FPBits<T> bits(sign ? FloatProp::SIGN_MASK : UIntType(0));
158158
bits.set_unbiased_exponent(MAX_EXPONENT);
159159
return bits;
160160
}

libc/src/math/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ add_math_entrypoint_object(copysignl)
7676

7777
add_math_entrypoint_object(cos)
7878
add_math_entrypoint_object(cosf)
79+
add_math_entrypoint_object(coshf)
7980

8081
add_math_entrypoint_object(expf)
8182

libc/src/math/coshf.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for coshf -------------------------*- 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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_MATH_COSHF_H
10+
#define LLVM_LIBC_SRC_MATH_COSHF_H
11+
12+
namespace __llvm_libc {
13+
14+
float coshf(float x);
15+
16+
} // namespace __llvm_libc
17+
18+
#endif // LLVM_LIBC_SRC_MATH_COSHF_H

libc/src/math/generic/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,3 +1128,22 @@ add_entrypoint_object(
11281128
COMPILE_OPTIONS
11291129
-O3
11301130
)
1131+
1132+
add_entrypoint_object(
1133+
coshf
1134+
SRCS
1135+
coshf.cpp
1136+
HDRS
1137+
../coshf.h
1138+
expxf.h
1139+
DEPENDS
1140+
.common_constants
1141+
libc.src.__support.FPUtil.fputil
1142+
libc.src.__support.FPUtil.multiply_add
1143+
libc.src.__support.FPUtil.nearest_integer
1144+
libc.src.__support.FPUtil.polyeval
1145+
libc.include.math
1146+
COMPILE_OPTIONS
1147+
-O3
1148+
)
1149+

libc/src/math/generic/coshf.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===-- Single-precision cosh 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/coshf.h"
10+
#include "src/__support/FPUtil/FPBits.h"
11+
#include "src/__support/FPUtil/multiply_add.h"
12+
#include "src/math/generic/expxf.h"
13+
14+
namespace __llvm_libc {
15+
16+
LLVM_LIBC_FUNCTION(float, coshf, (float x)) {
17+
using FPBits = typename fputil::FPBits<float>;
18+
FPBits xbits(x);
19+
xbits.set_sign(false);
20+
x = xbits.get_val();
21+
22+
uint32_t x_u = xbits.uintval();
23+
24+
// |x| <= 2^-26
25+
if (unlikely(x_u <= 0x3280'0000U)) {
26+
return 1.0f + x;
27+
}
28+
29+
// When |x| >= 90, or x is inf or nan
30+
if (unlikely(x_u >= 0x42b4'0000U)) {
31+
if (xbits.is_inf_or_nan())
32+
return x + FPBits::inf().get_val();
33+
34+
int rounding = fputil::get_round();
35+
if (unlikely(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO))
36+
return FPBits(FPBits::MAX_NORMAL).get_val();
37+
38+
errno = ERANGE;
39+
40+
return x + FPBits::inf().get_val();
41+
}
42+
auto ep_p = exp_eval<-1>(x);
43+
auto ep_m = exp_eval<-1>(-x);
44+
// 0.5 * exp(x) = ep_p.mult_exp * (ep_p.r + 1)
45+
// = ep_p.mult_exp * ep_p.r + ep_p.mult_exp
46+
// 0.5 * exp(-x) = ep_m.mult_exp * (ep_m.r + 1)
47+
// = ep_m.mult_exp * ep_m.r + ep_m.mult_exp
48+
// cos(x) = 0.5 * exp(x) + 0.5 * expm1(-x)
49+
double ep = fputil::multiply_add(ep_p.mult_exp, ep_p.r, ep_p.mult_exp) +
50+
fputil::multiply_add(ep_m.mult_exp, ep_m.r, ep_m.mult_exp);
51+
return ep;
52+
}
53+
54+
} // namespace __llvm_libc

libc/test/src/math/CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,22 @@ add_fp_unittest(
13141314
libc.src.__support.FPUtil.fputil
13151315
)
13161316

1317+
add_fp_unittest(
1318+
coshf_test
1319+
NEED_MPFR
1320+
SUITE
1321+
libc_math_unittests
1322+
SRCS
1323+
coshf_test.cpp
1324+
HDRS
1325+
sdcomp26094.h
1326+
DEPENDS
1327+
libc.include.errno
1328+
libc.src.math.coshf
1329+
libc.src.__support.CPP.array
1330+
libc.src.__support.FPUtil.fputil
1331+
)
1332+
13171333
add_subdirectory(generic)
13181334
add_subdirectory(exhaustive)
13191335
add_subdirectory(differential_testing)

libc/test/src/math/coshf_test.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//===-- Unittests for coshf -----------------------------------------------===//
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/__support/CPP/Array.h"
10+
#include "src/__support/FPUtil/FPBits.h"
11+
#include "src/math/coshf.h"
12+
#include "utils/MPFRWrapper/MPFRUtils.h"
13+
#include "utils/UnitTest/FPMatcher.h"
14+
#include "utils/UnitTest/Test.h"
15+
#include <math.h>
16+
17+
#include <errno.h>
18+
#include <stdint.h>
19+
20+
using FPBits = __llvm_libc::fputil::FPBits<float>;
21+
22+
namespace mpfr = __llvm_libc::testing::mpfr;
23+
24+
DECLARE_SPECIAL_CONSTANTS(float)
25+
26+
TEST(LlvmLibcCoshfTest, SpecialNumbers) {
27+
errno = 0;
28+
29+
EXPECT_FP_EQ(aNaN, __llvm_libc::coshf(aNaN));
30+
EXPECT_MATH_ERRNO(0);
31+
32+
EXPECT_FP_EQ(inf, __llvm_libc::coshf(inf));
33+
EXPECT_MATH_ERRNO(0);
34+
35+
EXPECT_FP_EQ(inf, __llvm_libc::coshf(neg_inf));
36+
EXPECT_MATH_ERRNO(0);
37+
38+
EXPECT_FP_EQ(1.0f, __llvm_libc::coshf(0.0f));
39+
EXPECT_MATH_ERRNO(0);
40+
41+
EXPECT_FP_EQ(1.0f, __llvm_libc::coshf(-0.0f));
42+
EXPECT_MATH_ERRNO(0);
43+
}
44+
45+
TEST(LlvmLibcCoshfTest, Overflow) {
46+
errno = 0;
47+
EXPECT_FP_EQ(inf, __llvm_libc::coshf(float(FPBits(0x7f7fffffU))));
48+
EXPECT_MATH_ERRNO(ERANGE);
49+
50+
EXPECT_FP_EQ(inf, __llvm_libc::coshf(float(FPBits(0x42cffff8U))));
51+
EXPECT_MATH_ERRNO(ERANGE);
52+
53+
EXPECT_FP_EQ(inf, __llvm_libc::coshf(float(FPBits(0x42d00008U))));
54+
EXPECT_MATH_ERRNO(ERANGE);
55+
}
56+
57+
TEST(LlvmLibcCoshfTest, InFloatRange) {
58+
constexpr uint32_t COUNT = 1000000;
59+
constexpr uint32_t STEP = UINT32_MAX / COUNT;
60+
for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
61+
float x = float(FPBits(v));
62+
if (isnan(x) || isinf(x))
63+
continue;
64+
ASSERT_MPFR_MATCH(mpfr::Operation::Cosh, x, __llvm_libc::coshf(x), 0.5);
65+
}
66+
}
67+
68+
TEST(LlvmLibcCoshfTest, SmallValues) {
69+
float x = float(FPBits(0x17800000U));
70+
float result = __llvm_libc::coshf(x);
71+
EXPECT_MPFR_MATCH(mpfr::Operation::Cosh, x, result, 0.5);
72+
EXPECT_FP_EQ(1.0f, result);
73+
74+
x = float(FPBits(0x0040000U));
75+
result = __llvm_libc::coshf(x);
76+
EXPECT_MPFR_MATCH(mpfr::Operation::Cosh, x, result, 0.5);
77+
EXPECT_FP_EQ(1.0f, result);
78+
}

libc/test/src/math/exhaustive/CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,21 @@ add_fp_unittest(
201201
libc.src.__support.FPUtil.fputil
202202
libc.src.__support.FPUtil.generic.fmod
203203
)
204+
205+
add_fp_unittest(
206+
coshf_test
207+
NO_RUN_POSTBUILD
208+
NEED_MPFR
209+
SUITE
210+
libc_math_exhaustive_tests
211+
SRCS
212+
coshf_test.cpp
213+
DEPENDS
214+
.exhaustive_test
215+
libc.include.math
216+
libc.src.math.coshf
217+
libc.src.__support.FPUtil.fputil
218+
LINK_LIBRARIES
219+
-lpthread
220+
)
221+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===-- Exhaustive test for coshf -----------------------------------------===//
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 "exhaustive_test.h"
10+
#include "src/__support/FPUtil/FPBits.h"
11+
#include "src/math/coshf.h"
12+
#include "utils/MPFRWrapper/MPFRUtils.h"
13+
#include "utils/UnitTest/FPMatcher.h"
14+
15+
#include <thread>
16+
17+
using FPBits = __llvm_libc::fputil::FPBits<float>;
18+
19+
namespace mpfr = __llvm_libc::testing::mpfr;
20+
21+
struct LlvmLibcCoshfExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
22+
bool check(uint32_t start, uint32_t stop,
23+
mpfr::RoundingMode rounding) override {
24+
mpfr::ForceRoundingMode r(rounding);
25+
uint32_t bits = start;
26+
bool result = true;
27+
do {
28+
FPBits xbits(bits);
29+
float x = float(xbits);
30+
result &= EXPECT_MPFR_MATCH(mpfr::Operation::Cosh, x,
31+
__llvm_libc::coshf(x), 0.5, rounding);
32+
} while (bits++ < stop);
33+
return result;
34+
}
35+
};
36+
37+
// Range: [0, 90];
38+
static constexpr uint32_t POS_START = 0x0000'0000U;
39+
static constexpr uint32_t POS_STOP = 0x42b4'0000U;
40+
41+
TEST_F(LlvmLibcCoshfExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
42+
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
43+
}
44+
45+
TEST_F(LlvmLibcCoshfExhaustiveTest, PostiveRangeRoundUp) {
46+
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Upward);
47+
}
48+
49+
TEST_F(LlvmLibcCoshfExhaustiveTest, PostiveRangeRoundDown) {
50+
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Downward);
51+
}
52+
53+
TEST_F(LlvmLibcCoshfExhaustiveTest, PostiveRangeRoundTowardZero) {
54+
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::TowardZero);
55+
}

libc/utils/MPFRWrapper/MPFRUtils.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ class MPFRNumber {
194194
return result;
195195
}
196196

197+
MPFRNumber cosh() const {
198+
MPFRNumber result(*this);
199+
mpfr_cosh(result.value, value, mpfr_rounding);
200+
return result;
201+
}
202+
197203
MPFRNumber exp() const {
198204
MPFRNumber result(*this);
199205
mpfr_exp(result.value, value, mpfr_rounding);
@@ -481,6 +487,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
481487
return mpfrInput.ceil();
482488
case Operation::Cos:
483489
return mpfrInput.cos();
490+
case Operation::Cosh:
491+
return mpfrInput.cosh();
484492
case Operation::Exp:
485493
return mpfrInput.exp();
486494
case Operation::Exp2:

libc/utils/MPFRWrapper/MPFRUtils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ enum class Operation : int {
2727
Abs,
2828
Ceil,
2929
Cos,
30+
Cosh,
3031
Exp,
3132
Exp2,
3233
Expm1,

0 commit comments

Comments
 (0)