"expf",
"exp2f",
"round",
+ "roundf",
"sincosf",
"sinf",
"trunc",
libc.src.math.floor
libc.src.math.floorf
libc.src.math.round
+ libc.src.math.roundf
libc.src.math.sincosf
libc.src.math.sinf
libc.src.math.trunc
DEPENDS
${TARGET_LIBM_ENTRYPOINTS}
)
-
-add_redirector_library(
- llvmlibc_redirectors
- DEPENDS
- round_redirector
-)
FunctionSpec<"exp2f", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"round", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
+ FunctionSpec<"roundf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"trunc", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
FunctionSpec<"truncf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
)
add_entrypoint_object(
- round
- REDIRECTED
- SRCS
- round.cpp
- HDRS
- round.h
-)
-
-add_redirector_object(
- round_redirector
- SRC
- round_redirector.cpp
-)
-
-add_entrypoint_object(
cosf
SRCS
cosf.cpp
libc.utils.FPUtil.fputil
)
+add_entrypoint_object(
+ round
+ SRCS
+ round.cpp
+ HDRS
+ round.h
+ DEPENDS
+ libc.utils.FPUtil.fputil
+)
+
+add_entrypoint_object(
+ roundf
+ SRCS
+ roundf.cpp
+ HDRS
+ roundf.h
+ DEPENDS
+ libc.utils.FPUtil.fputil
+)
+
add_object_library(
exp_utils
HDRS
-//===-- Implementation of round -------------------------------------------===//
+//===-- Implementation of round function ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
//
//===----------------------------------------------------------------------===//
-#include "src/math/round.h"
-
#include "src/__support/common.h"
+#include "utils/FPUtil/FloatOperations.h"
namespace __llvm_libc {
-double __round_redirector(double x);
-
-double LLVM_LIBC_ENTRYPOINT(round)(double x) {
- return __round_redirector(x);
-}
+double LLVM_LIBC_ENTRYPOINT(round)(double x) { return fputil::round(x); }
} // namespace __llvm_libc
-//===-- Implementation of round redirector --------------------------------===//
+//===-- Implementation of roundf function ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
//
//===----------------------------------------------------------------------===//
-// Include okay for this redirector.
-// NOLINTNEXTLINE(llvmlibc-restrict-system-libc-headers)
-#include <math.h>
+#include "src/__support/common.h"
+#include "utils/FPUtil/FloatOperations.h"
namespace __llvm_libc {
-double __round_redirector(double x) {
- return ::round(x);
-}
+float LLVM_LIBC_ENTRYPOINT(roundf)(float x) { return fputil::round(x); }
} // namespace __llvm_libc
--- /dev/null
+//===-- Implementation header for roundf ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_ROUNDF_H
+#define LLVM_LIBC_SRC_MATH_ROUNDF_H
+
+namespace __llvm_libc {
+
+float roundf(float x);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_MATH_ROUNDF_H
)
add_math_unittest(
+ round_test
+ NEED_MPFR
+ SUITE
+ libc_math_unittests
+ SRCS
+ round_test.cpp
+ DEPENDS
+ libc.include.math
+ libc.src.math.round
+ libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
+ roundf_test
+ NEED_MPFR
+ SUITE
+ libc_math_unittests
+ SRCS
+ roundf_test.cpp
+ DEPENDS
+ libc.include.math
+ libc.src.math.roundf
+ libc.utils.FPUtil.fputil
+)
+
+add_math_unittest(
expf_test
NEED_MPFR
SUITE
--- /dev/null
+//===-- Unittests for round -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/round.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<double>;
+using Properties = __llvm_libc::fputil::FloatProperties<double>;
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+// Zero tolerance; As in, exact match with MPFR result.
+static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
+ 0};
+
+TEST(RoundTest, SpecialNumbers) {
+ EXPECT_EQ(
+ BitPatterns::aQuietNaN,
+ valueAsBits(__llvm_libc::round(valueFromBits(BitPatterns::aQuietNaN))));
+ EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+ valueAsBits(__llvm_libc::round(
+ valueFromBits(BitPatterns::aNegativeQuietNaN))));
+
+ EXPECT_EQ(BitPatterns::aSignallingNaN,
+ valueAsBits(__llvm_libc::round(
+ valueFromBits(BitPatterns::aSignallingNaN))));
+ EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
+ valueAsBits(__llvm_libc::round(
+ valueFromBits(BitPatterns::aNegativeSignallingNaN))));
+
+ EXPECT_EQ(BitPatterns::inf,
+ valueAsBits(__llvm_libc::round(valueFromBits(BitPatterns::inf))));
+ EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::round(
+ valueFromBits(BitPatterns::negInf))));
+
+ EXPECT_EQ(BitPatterns::zero,
+ valueAsBits(__llvm_libc::round(valueFromBits(BitPatterns::zero))));
+ EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::round(
+ valueFromBits(BitPatterns::negZero))));
+}
+
+TEST(RoundTest, RoundedNumbers) {
+ EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::round(1.0)));
+ EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::round(-1.0)));
+ EXPECT_EQ(valueAsBits(10.0), valueAsBits(__llvm_libc::round(10.0)));
+ EXPECT_EQ(valueAsBits(-10.0), valueAsBits(__llvm_libc::round(-10.0)));
+ EXPECT_EQ(valueAsBits(12345.0), valueAsBits(__llvm_libc::round(12345.0)));
+ EXPECT_EQ(valueAsBits(-12345.0), valueAsBits(__llvm_libc::round(-12345.0)));
+}
+
+TEST(RoundTest, CloseToZeroNumbers) {
+ EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::round(0.5)));
+ EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::round(-0.5)));
+ EXPECT_EQ(valueAsBits(0.0), valueAsBits(__llvm_libc::round(0.115)));
+ EXPECT_EQ(valueAsBits(-0.0), valueAsBits(__llvm_libc::round(-0.115)));
+ EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::round(0.715)));
+ EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::round(-0.715)));
+}
+
+TEST(RoundTest, InDoubleRange) {
+ using BitsType = Properties::BitsType;
+ constexpr BitsType count = 1000000;
+ constexpr BitsType step = UINT64_MAX / count;
+ for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+ double x = valueFromBits(v);
+ if (isnan(x) || isinf(x))
+ continue;
+ ASSERT_MPFR_MATCH(mpfr::Operation::Round, x, __llvm_libc::round(x),
+ tolerance);
+ }
+}
--- /dev/null
+//===-- Unittests for roundf ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/math.h"
+#include "src/math/roundf.h"
+#include "utils/FPUtil/BitPatterns.h"
+#include "utils/FPUtil/FloatOperations.h"
+#include "utils/FPUtil/FloatProperties.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::fputil::valueAsBits;
+using __llvm_libc::fputil::valueFromBits;
+
+using BitPatterns = __llvm_libc::fputil::BitPatterns<float>;
+using Properties = __llvm_libc::fputil::FloatProperties<float>;
+
+namespace mpfr = __llvm_libc::testing::mpfr;
+
+// Zero tolerance; As in, exact match with MPFR result.
+static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
+ 0};
+
+TEST(RoundfTest, SpecialNumbers) {
+ EXPECT_EQ(
+ BitPatterns::aQuietNaN,
+ valueAsBits(__llvm_libc::roundf(valueFromBits(BitPatterns::aQuietNaN))));
+ EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
+ valueAsBits(__llvm_libc::roundf(
+ valueFromBits(BitPatterns::aNegativeQuietNaN))));
+
+ EXPECT_EQ(BitPatterns::aSignallingNaN,
+ valueAsBits(__llvm_libc::roundf(
+ valueFromBits(BitPatterns::aSignallingNaN))));
+ EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
+ valueAsBits(__llvm_libc::roundf(
+ valueFromBits(BitPatterns::aNegativeSignallingNaN))));
+
+ EXPECT_EQ(BitPatterns::inf,
+ valueAsBits(__llvm_libc::roundf(valueFromBits(BitPatterns::inf))));
+ EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::roundf(
+ valueFromBits(BitPatterns::negInf))));
+
+ EXPECT_EQ(BitPatterns::zero,
+ valueAsBits(__llvm_libc::roundf(valueFromBits(BitPatterns::zero))));
+ EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::roundf(
+ valueFromBits(BitPatterns::negZero))));
+}
+
+TEST(RoundfTest, RoundedNumbers) {
+ EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::roundf(1.0f)));
+ EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::roundf(-1.0f)));
+ EXPECT_EQ(valueAsBits(10.0f), valueAsBits(__llvm_libc::roundf(10.0f)));
+ EXPECT_EQ(valueAsBits(-10.0f), valueAsBits(__llvm_libc::roundf(-10.0f)));
+ EXPECT_EQ(valueAsBits(12345.0f), valueAsBits(__llvm_libc::roundf(12345.0f)));
+ EXPECT_EQ(valueAsBits(-12345.0f),
+ valueAsBits(__llvm_libc::roundf(-12345.0f)));
+}
+
+TEST(RoundTest, CloseToZeroNumbers) {
+ EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::roundf(0.5f)));
+ EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::roundf(-0.5f)));
+ EXPECT_EQ(valueAsBits(0.0f), valueAsBits(__llvm_libc::roundf(0.115f)));
+ EXPECT_EQ(valueAsBits(-0.0f), valueAsBits(__llvm_libc::roundf(-0.115f)));
+ EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::roundf(0.715f)));
+ EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::roundf(-0.715f)));
+}
+
+TEST(RoundfTest, InFloatRange) {
+ using BitsType = Properties::BitsType;
+ constexpr BitsType count = 1000000;
+ constexpr BitsType step = UINT32_MAX / count;
+ for (BitsType i = 0, v = 0; i <= count; ++i, v += step) {
+ double x = valueFromBits(v);
+ if (isnan(x) || isinf(x))
+ continue;
+ ASSERT_MPFR_MATCH(mpfr::Operation::Round, x, __llvm_libc::roundf(x),
+ tolerance);
+ }
+}
}
}
+template <typename T,
+ cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
+static inline T round(T x) {
+ using Properties = FloatProperties<T>;
+ using BitsType = typename FloatProperties<T>::BitsType;
+
+ BitsType bits = valueAsBits(x);
+
+ // If x is infinity, NaN or zero, return it.
+ if (bitsAreInfOrNaN(bits) || bitsAreZero(bits))
+ return x;
+
+ bool isNeg = bits & Properties::signMask;
+ int exponent = getExponentFromBits(bits);
+
+ // If the exponent is greater than the most negative mantissa
+ // exponent, then x is already an integer.
+ if (exponent >= static_cast<int>(Properties::mantissaWidth))
+ return x;
+
+ if (exponent == -1) {
+ // Absolute value of x is greater than equal to 0.5 but less than 1.
+ if (isNeg)
+ return T(-1.0);
+ else
+ return T(1.0);
+ }
+
+ if (exponent <= -2) {
+ // Absolute value of x is less than 0.5.
+ if (isNeg)
+ return T(-0.0);
+ else
+ return T(0.0);
+ }
+
+ uint32_t trimSize = Properties::mantissaWidth - exponent;
+ // If x is already an integer, return it.
+ if ((bits << (Properties::bitWidth - trimSize)) == 0)
+ return x;
+
+ BitsType truncBits = (bits >> trimSize) << trimSize;
+ T truncValue = valueFromBits(truncBits);
+
+ if ((bits & (BitsType(1) << (trimSize - 1))) == 0) {
+ // Franctional part is less than 0.5 so round value is the
+ // same as the trunc value.
+ return truncValue;
+ }
+
+ if (isNeg)
+ return truncValue - T(1.0);
+ else
+ return truncValue + T(1.0);
+}
+
} // namespace fputil
} // namespace __llvm_libc