forked from OSchip/llvm-project
[libc] Add implementations of round and roundf.
Reviewers: asteinhauser Differential Revision: https://reviews.llvm.org/D80779
This commit is contained in:
parent
9ec57cce62
commit
4be1c116ad
|
@ -160,6 +160,7 @@ def MathAPI : PublicAPI<"math.h"> {
|
|||
"expf",
|
||||
"exp2f",
|
||||
"round",
|
||||
"roundf",
|
||||
"sincosf",
|
||||
"sinf",
|
||||
"trunc",
|
||||
|
|
|
@ -55,6 +55,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
|||
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
|
||||
|
|
|
@ -9,9 +9,3 @@ add_entrypoint_library(
|
|||
DEPENDS
|
||||
${TARGET_LIBM_ENTRYPOINTS}
|
||||
)
|
||||
|
||||
add_redirector_library(
|
||||
llvmlibc_redirectors
|
||||
DEPENDS
|
||||
round_redirector
|
||||
)
|
||||
|
|
|
@ -203,6 +203,7 @@ def StdC : StandardSpec<"stdc"> {
|
|||
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>]>,
|
||||
|
|
|
@ -20,21 +20,6 @@ add_object_library(
|
|||
.math_utils
|
||||
)
|
||||
|
||||
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
|
||||
|
@ -151,6 +136,26 @@ add_entrypoint_object(
|
|||
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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===-- 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.
|
||||
|
@ -6,16 +6,11 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===-- 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.
|
||||
|
@ -6,14 +6,11 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// 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
|
|
@ -0,0 +1,18 @@
|
|||
//===-- 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
|
|
@ -175,6 +175,32 @@ add_math_unittest(
|
|||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
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
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
//===-- 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
//===-- 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);
|
||||
}
|
||||
}
|
|
@ -214,6 +214,62 @@ static inline T floor(T x) {
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
|
Loading…
Reference in New Issue