Skip to content

Commit be720c5

Browse files
committed
[libc] Implement roundeven C23 math functions
1 parent d6713ad commit be720c5

25 files changed

+570
-1
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,10 @@ set(TARGET_LIBM_ENTRYPOINTS
494494
libc.src.math.round
495495
libc.src.math.roundf
496496
libc.src.math.roundl
497+
libc.src.math.roundeven
498+
libc.src.math.roundevenf
499+
libc.src.math.roundevenl
500+
libc.src.math.roundevenf128
497501
libc.src.math.scalbn
498502
libc.src.math.scalbnf
499503
libc.src.math.scalbnl

libc/docs/math/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ Basic Operations
206206
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
207207
| round | |check| | |check| | |check| | | |check| | 7.12.9.6 | F.10.6.6 |
208208
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
209-
| roundeven | | | | | | 7.12.9.8 | F.10.6.8 |
209+
| roundeven | |check| | |check| | |check| | | |check| | 7.12.9.8 | F.10.6.8 |
210210
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
211211
| scalbn | |check| | |check| | |check| | | | 7.12.6.19 | F.10.3.19 |
212212
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+

libc/src/math/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ add_math_entrypoint_object(roundf)
293293
add_math_entrypoint_object(roundl)
294294
add_math_entrypoint_object(roundf128)
295295

296+
add_math_entrypoint_object(roundeven)
297+
add_math_entrypoint_object(roundevenf)
298+
add_math_entrypoint_object(roundevenl)
299+
add_math_entrypoint_object(roundevenf128)
300+
296301
add_math_entrypoint_object(scalbn)
297302
add_math_entrypoint_object(scalbnf)
298303
add_math_entrypoint_object(scalbnl)

libc/src/math/generic/CMakeLists.txt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,55 @@ add_entrypoint_object(
417417
libc.src.__support.FPUtil.nearest_integer_operations
418418
)
419419

420+
add_entrypoint_object(
421+
roundeven
422+
SRCS
423+
roundeven.cpp
424+
HDRS
425+
../roundeven.h
426+
COMPILE_OPTIONS
427+
-O3
428+
DEPENDS
429+
libc.src.__support.FPUtil.nearest_integer_operations
430+
)
431+
432+
add_entrypoint_object(
433+
roundevenf
434+
SRCS
435+
roundevenf.cpp
436+
HDRS
437+
../roundevenf.h
438+
COMPILE_OPTIONS
439+
-O3
440+
DEPENDS
441+
libc.src.__support.FPUtil.nearest_integer_operations
442+
)
443+
444+
add_entrypoint_object(
445+
roundevenl
446+
SRCS
447+
roundevenl.cpp
448+
HDRS
449+
../roundevenl.h
450+
COMPILE_OPTIONS
451+
-O3
452+
DEPENDS
453+
libc.src.__support.FPUtil.nearest_integer_operations
454+
)
455+
456+
add_entrypoint_object(
457+
roundevenf128
458+
SRCS
459+
roundevenf128.cpp
460+
HDRS
461+
../roundevenf128.h
462+
COMPILE_OPTIONS
463+
-O3
464+
DEPENDS
465+
libc.src.__support.macros.properties.types
466+
libc.src.__support.FPUtil.nearest_integer_operations
467+
)
468+
420469
add_entrypoint_object(
421470
lround
422471
SRCS

libc/src/math/generic/roundeven.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of roundeven 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/roundeven.h"
10+
#include "src/__support/FPUtil/NearestIntegerOperations.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(double, roundeven, (double x)) {
16+
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE

libc/src/math/generic/roundevenf.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of roundevenf 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/roundevenf.h"
10+
#include "src/__support/FPUtil/NearestIntegerOperations.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(float, roundevenf, (float x)) {
16+
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of roundevenf128 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/roundevenf128.h"
10+
#include "src/__support/FPUtil/NearestIntegerOperations.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(float128, roundevenf128, (float128 x)) {
16+
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE

libc/src/math/generic/roundevenl.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of roundevenl 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/roundevenl.h"
10+
#include "src/__support/FPUtil/NearestIntegerOperations.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(long double, roundevenl, (long double x)) {
16+
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE

libc/src/math/roundeven.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for roundeven ---------------------*- 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_ROUNDEVEN_H
10+
#define LLVM_LIBC_SRC_MATH_ROUNDEVEN_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
double roundeven(double x);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_ROUNDEVEN_H

libc/src/math/roundevenf.h

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

libc/src/math/roundevenf128.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header for roundevenf128 -----------------*- 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_ROUNDEVENF128_H
10+
#define LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H
11+
12+
#include "src/__support/macros/properties/types.h"
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
float128 roundevenf128(float128 x);
17+
18+
} // namespace LIBC_NAMESPACE
19+
20+
#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H

libc/src/math/roundevenl.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for roundevenl --------------------*- 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_ROUNDEVENL_H
10+
#define LLVM_LIBC_SRC_MATH_ROUNDEVENL_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
long double roundevenl(long double x);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENL_H

libc/test/src/math/CMakeLists.txt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,51 @@ add_fp_unittest(
323323
libc.src.__support.FPUtil.fp_bits
324324
)
325325

326+
add_fp_unittest(
327+
roundeven_test
328+
NEED_MPFR
329+
SUITE
330+
libc-math-unittests
331+
SRCS
332+
roundeven_test.cpp
333+
HDRS
334+
RoundEvenTest.h
335+
DEPENDS
336+
libc.include.math
337+
libc.src.math.roundeven
338+
libc.src.__support.FPUtil.fp_bits
339+
)
340+
341+
add_fp_unittest(
342+
roundevenf_test
343+
NEED_MPFR
344+
SUITE
345+
libc-math-unittests
346+
SRCS
347+
roundevenf_test.cpp
348+
HDRS
349+
RoundEvenTest.h
350+
DEPENDS
351+
libc.include.math
352+
libc.src.math.roundevenf
353+
libc.src.__support.FPUtil.fp_bits
354+
)
355+
356+
add_fp_unittest(
357+
roundevenl_test
358+
NEED_MPFR
359+
SUITE
360+
libc-math-unittests
361+
SRCS
362+
roundevenl_test.cpp
363+
HDRS
364+
RoundEvenTest.h
365+
DEPENDS
366+
libc.include.math
367+
libc.src.math.roundevenl
368+
libc.src.__support.FPUtil.fp_bits
369+
)
370+
326371
add_fp_unittest(
327372
lround_test
328373
NEED_MPFR

libc/test/src/math/RoundEvenTest.h

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//===-- Utility class to test roundeven[f|l] --------------------*- 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_TEST_SRC_MATH_ROUNDEVENTEST_H
10+
#define LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H
11+
12+
#include "test/UnitTest/FPMatcher.h"
13+
#include "test/UnitTest/Test.h"
14+
#include "utils/MPFRWrapper/MPFRUtils.h"
15+
16+
#include "include/llvm-libc-macros/math-macros.h"
17+
18+
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
19+
20+
template <typename T>
21+
class RoundEvenTest : public LIBC_NAMESPACE::testing::Test {
22+
23+
DECLARE_SPECIAL_CONSTANTS(T)
24+
25+
public:
26+
typedef T (*RoundEvenFunc)(T);
27+
28+
void testSpecialNumbers(RoundEvenFunc func) {
29+
EXPECT_FP_EQ(zero, func(zero));
30+
EXPECT_FP_EQ(neg_zero, func(neg_zero));
31+
32+
EXPECT_FP_EQ(inf, func(inf));
33+
EXPECT_FP_EQ(neg_inf, func(neg_inf));
34+
35+
EXPECT_FP_EQ(aNaN, func(aNaN));
36+
}
37+
38+
void testRoundedNumbers(RoundEvenFunc func) {
39+
EXPECT_FP_EQ(T(1.0), func(T(1.0)));
40+
EXPECT_FP_EQ(T(-1.0), func(T(-1.0)));
41+
EXPECT_FP_EQ(T(10.0), func(T(10.0)));
42+
EXPECT_FP_EQ(T(-10.0), func(T(-10.0)));
43+
EXPECT_FP_EQ(T(1234.0), func(T(1234.0)));
44+
EXPECT_FP_EQ(T(-1234.0), func(T(-1234.0)));
45+
}
46+
47+
void testFractions(RoundEvenFunc func) {
48+
EXPECT_FP_EQ(T(0.0), func(T(0.5)));
49+
EXPECT_FP_EQ(T(-0.0), func(T(-0.5)));
50+
EXPECT_FP_EQ(T(0.0), func(T(0.115)));
51+
EXPECT_FP_EQ(T(-0.0), func(T(-0.115)));
52+
EXPECT_FP_EQ(T(1.0), func(T(0.715)));
53+
EXPECT_FP_EQ(T(-1.0), func(T(-0.715)));
54+
EXPECT_FP_EQ(T(1.0), func(T(1.3)));
55+
EXPECT_FP_EQ(T(-1.0), func(T(-1.3)));
56+
EXPECT_FP_EQ(T(2.0), func(T(1.5)));
57+
EXPECT_FP_EQ(T(-2.0), func(T(-1.5)));
58+
EXPECT_FP_EQ(T(2.0), func(T(1.75)));
59+
EXPECT_FP_EQ(T(-2.0), func(T(-1.75)));
60+
EXPECT_FP_EQ(T(11.0), func(T(10.65)));
61+
EXPECT_FP_EQ(T(-11.0), func(T(-10.65)));
62+
EXPECT_FP_EQ(T(1233.0), func(T(1233.25)));
63+
EXPECT_FP_EQ(T(1234.0), func(T(1233.50)));
64+
EXPECT_FP_EQ(T(1234.0), func(T(1233.75)));
65+
EXPECT_FP_EQ(T(-1233.0), func(T(-1233.25)));
66+
EXPECT_FP_EQ(T(-1234.0), func(T(-1233.50)));
67+
EXPECT_FP_EQ(T(-1234.0), func(T(-1233.75)));
68+
EXPECT_FP_EQ(T(1234.0), func(T(1234.50)));
69+
EXPECT_FP_EQ(T(-1234.0), func(T(-1234.50)));
70+
}
71+
72+
void testRange(RoundEvenFunc func) {
73+
constexpr StorageType COUNT = 100'000;
74+
constexpr StorageType STEP = STORAGE_MAX / COUNT;
75+
for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
76+
T x = FPBits(v).get_val();
77+
if (isnan(x) || isinf(x))
78+
continue;
79+
80+
ASSERT_MPFR_MATCH(mpfr::Operation::RoundEven, x, func(x), 0.0);
81+
}
82+
}
83+
};
84+
85+
#define LIST_ROUNDEVEN_TESTS(T, func) \
86+
using LlvmLibcRoundEvenTest = RoundEvenTest<T>; \
87+
TEST_F(LlvmLibcRoundEvenTest, SpecialNumbers) { testSpecialNumbers(&func); } \
88+
TEST_F(LlvmLibcRoundEvenTest, RoundedNubmers) { testRoundedNumbers(&func); } \
89+
TEST_F(LlvmLibcRoundEvenTest, Fractions) { testFractions(&func); } \
90+
TEST_F(LlvmLibcRoundEvenTest, Range) { testRange(&func); }
91+
92+
#endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H

0 commit comments

Comments
 (0)