[libc] Add implementations of rounding functions which depend rounding mode.

Namely, implementations for rint, rintf, rintl, lrint, lrintf, lrintl,
llrint, llrintf and llrintl have been added.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D93889
This commit is contained in:
Siva Chandra Reddy 2020-12-21 09:16:41 -08:00
parent 981a0bd858
commit ff6fd38552
36 changed files with 1147 additions and 49 deletions

View File

@ -123,12 +123,18 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.ldexp
libc.src.math.ldexpf
libc.src.math.ldexpl
libc.src.math.llrint
libc.src.math.llrintf
libc.src.math.llrintl
libc.src.math.llround
libc.src.math.llroundf
libc.src.math.llroundl
libc.src.math.logb
libc.src.math.logbf
libc.src.math.logbl
libc.src.math.lrint
libc.src.math.lrintf
libc.src.math.lrintl
libc.src.math.lround
libc.src.math.lroundf
libc.src.math.lroundl
@ -141,6 +147,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.remquof
libc.src.math.remquo
libc.src.math.remquol
libc.src.math.rint
libc.src.math.rintf
libc.src.math.rintl
libc.src.math.round
libc.src.math.roundf
libc.src.math.roundl

View File

@ -371,6 +371,18 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"llroundf", RetValSpec<LongLongType>, [ArgSpec<FloatType>]>,
FunctionSpec<"llroundl", RetValSpec<LongLongType>, [ArgSpec<LongDoubleType>]>,
FunctionSpec<"rint", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
FunctionSpec<"rintf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"rintl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
FunctionSpec<"lrint", RetValSpec<LongType>, [ArgSpec<DoubleType>]>,
FunctionSpec<"lrintf", RetValSpec<LongType>, [ArgSpec<FloatType>]>,
FunctionSpec<"lrintl", RetValSpec<LongType>, [ArgSpec<LongDoubleType>]>,
FunctionSpec<"llrint", RetValSpec<LongLongType>, [ArgSpec<DoubleType>]>,
FunctionSpec<"llrintf", RetValSpec<LongLongType>, [ArgSpec<FloatType>]>,
FunctionSpec<"llrintl", RetValSpec<LongLongType>, [ArgSpec<LongDoubleType>]>,
FunctionSpec<"sqrt", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
FunctionSpec<"sqrtf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
FunctionSpec<"sqrtl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,

View File

@ -308,6 +308,114 @@ add_entrypoint_object(
-O2
)
add_entrypoint_object(
rint
SRCS
rint.cpp
HDRS
rint.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_entrypoint_object(
rintf
SRCS
rintf.cpp
HDRS
rintf.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_entrypoint_object(
rintl
SRCS
rintl.cpp
HDRS
rintl.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_entrypoint_object(
lrint
SRCS
lrint.cpp
HDRS
lrint.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_entrypoint_object(
lrintf
SRCS
lrintf.cpp
HDRS
lrintf.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_entrypoint_object(
lrintl
SRCS
lrintl.cpp
HDRS
lrintl.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_entrypoint_object(
llrint
SRCS
llrint.cpp
HDRS
llrint.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_entrypoint_object(
llrintf
SRCS
llrintf.cpp
HDRS
llrintf.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_entrypoint_object(
llrintl
SRCS
llrintl.cpp
HDRS
llrintl.h
DEPENDS
libc.utils.FPUtil.fputil
COMPILE_OPTIONS
-O2
)
add_object_library(
exp_utils
HDRS

19
libc/src/math/llrint.cpp Normal file
View File

@ -0,0 +1,19 @@
//===-- Implementation of llrint function ---------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
long long LLVM_LIBC_ENTRYPOINT(llrint)(double x) {
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<double,
long long>(x);
}
} // namespace __llvm_libc

18
libc/src/math/llrint.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for llrint ------------------------*- 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_LLRINT_H
#define LLVM_LIBC_SRC_MATH_LLRINT_H
namespace __llvm_libc {
long long llrint(double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_LLRINT_H

19
libc/src/math/llrintf.cpp Normal file
View File

@ -0,0 +1,19 @@
//===-- Implementation of llrintf function --------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
long long LLVM_LIBC_ENTRYPOINT(llrintf)(float x) {
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<float, long long>(
x);
}
} // namespace __llvm_libc

18
libc/src/math/llrintf.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for llrintf -----------------------*- 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_LLRINTF_H
#define LLVM_LIBC_SRC_MATH_LLRINTF_H
namespace __llvm_libc {
long long llrintf(float x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_LLRINTF_H

19
libc/src/math/llrintl.cpp Normal file
View File

@ -0,0 +1,19 @@
//===-- Implementation of llrintl function --------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
long long LLVM_LIBC_ENTRYPOINT(llrintl)(long double x) {
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<long double,
long long>(x);
}
} // namespace __llvm_libc

18
libc/src/math/llrintl.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for llrintl -----------------------*- 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_LLRINTL_H
#define LLVM_LIBC_SRC_MATH_LLRINTL_H
namespace __llvm_libc {
long long llrintl(long double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_LLRINTL_H

18
libc/src/math/lrint.cpp Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation of lrint function ----------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
long LLVM_LIBC_ENTRYPOINT(lrint)(double x) {
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<double, long>(x);
}
} // namespace __llvm_libc

18
libc/src/math/lrint.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for lrint -------------------------*- 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_LRINT_H
#define LLVM_LIBC_SRC_MATH_LRINT_H
namespace __llvm_libc {
long lrint(double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_LRINT_H

18
libc/src/math/lrintf.cpp Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation of lrintf function ---------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
long LLVM_LIBC_ENTRYPOINT(lrintf)(float x) {
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<float, long>(x);
}
} // namespace __llvm_libc

18
libc/src/math/lrintf.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for lrintf ------------------------*- 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_LRINTF_H
#define LLVM_LIBC_SRC_MATH_LRINTF_H
namespace __llvm_libc {
long lrintf(float x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_LRINTF_H

19
libc/src/math/lrintl.cpp Normal file
View File

@ -0,0 +1,19 @@
//===-- Implementation of lrintl function ---------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
long LLVM_LIBC_ENTRYPOINT(lrintl)(long double x) {
return fputil::roundToSignedIntegerUsingCurrentRoundingMode<long double,
long>(x);
}
} // namespace __llvm_libc

18
libc/src/math/lrintl.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for lrintl ------------------------*- 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_LRINTL_H
#define LLVM_LIBC_SRC_MATH_LRINTL_H
namespace __llvm_libc {
long lrintl(long double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_LRINTL_H

18
libc/src/math/rint.cpp Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation of rint function -----------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
double LLVM_LIBC_ENTRYPOINT(rint)(double x) {
return fputil::roundUsingCurrentRoundingMode(x);
}
} // namespace __llvm_libc

18
libc/src/math/rint.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for rint --------------------------*- 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_RINT_H
#define LLVM_LIBC_SRC_MATH_RINT_H
namespace __llvm_libc {
double rint(double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_RINT_H

18
libc/src/math/rintf.cpp Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation of rintf function ----------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
float LLVM_LIBC_ENTRYPOINT(rintf)(float x) {
return fputil::roundUsingCurrentRoundingMode(x);
}
} // namespace __llvm_libc

18
libc/src/math/rintf.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for rintf -------------------------*- 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_RINTF_H
#define LLVM_LIBC_SRC_MATH_RINTF_H
namespace __llvm_libc {
float rintf(float x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_RINTF_H

18
libc/src/math/rintl.cpp Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation of rintl function ----------------------------------===//
//
// 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 "src/__support/common.h"
#include "utils/FPUtil/NearestIntegerOperations.h"
namespace __llvm_libc {
long double LLVM_LIBC_ENTRYPOINT(rintl)(long double x) {
return fputil::roundUsingCurrentRoundingMode(x);
}
} // namespace __llvm_libc

18
libc/src/math/rintl.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for rintl -------------------------*- 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_RINTL_H
#define LLVM_LIBC_SRC_MATH_RINTL_H
namespace __llvm_libc {
long double rintl(long double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_RINTL_H

View File

@ -390,6 +390,141 @@ add_fp_unittest(
libc.utils.FPUtil.fputil
)
add_fp_unittest(
rint_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
rint_test.cpp
HDRS
RIntTest.h
DEPENDS
libc.include.math
libc.src.math.rint
libc.utils.FPUtil.fputil
)
add_fp_unittest(
rintf_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
rintf_test.cpp
HDRS
RIntTest.h
DEPENDS
libc.include.math
libc.src.math.rintf
libc.utils.FPUtil.fputil
)
add_fp_unittest(
rintl_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
rintl_test.cpp
HDRS
RIntTest.h
DEPENDS
libc.include.math
libc.src.math.rintl
libc.utils.FPUtil.fputil
)
add_fp_unittest(
lrint_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
lrint_test.cpp
HDRS
RoundToIntegerTest.h
DEPENDS
libc.include.math
libc.src.math.lrint
libc.utils.FPUtil.fputil
)
add_fp_unittest(
lrintf_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
lrintf_test.cpp
HDRS
RoundToIntegerTest.h
DEPENDS
libc.include.math
libc.src.math.lrintf
libc.utils.FPUtil.fputil
)
add_fp_unittest(
lrintl_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
lrintl_test.cpp
HDRS
RoundToIntegerTest.h
DEPENDS
libc.include.math
libc.src.math.lrintl
libc.utils.FPUtil.fputil
)
add_fp_unittest(
llrint_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
llrint_test.cpp
HDRS
RoundToIntegerTest.h
DEPENDS
libc.include.math
libc.src.math.llrint
libc.utils.FPUtil.fputil
)
add_fp_unittest(
llrintf_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
llrintf_test.cpp
HDRS
RoundToIntegerTest.h
DEPENDS
libc.include.math
libc.src.math.llrintf
libc.utils.FPUtil.fputil
)
add_fp_unittest(
llrintl_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
llrintl_test.cpp
HDRS
RoundToIntegerTest.h
DEPENDS
libc.include.math
libc.src.math.llrintl
libc.utils.FPUtil.fputil
)
add_fp_unittest(
expf_test
NEED_MPFR

View File

@ -0,0 +1,138 @@
//===-- Utility class to test different flavors of rint ---------*- 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_TEST_SRC_MATH_RINTTEST_H
#define LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H
#include "utils/FPUtil/FEnv.h"
#include "utils/FPUtil/FPBits.h"
#include "utils/FPUtil/TestHelpers.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
#include "utils/UnitTest/Test.h"
#include <fenv.h>
#include <math.h>
#include <stdio.h>
namespace mpfr = __llvm_libc::testing::mpfr;
static constexpr int roundingModes[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
FE_TONEAREST};
template <typename T>
class RIntTestTemplate : public __llvm_libc::testing::Test {
public:
typedef T (*RIntFunc)(T);
private:
using FPBits = __llvm_libc::fputil::FPBits<T>;
using UIntType = typename FPBits::UIntType;
const T zero = FPBits::zero();
const T negZero = FPBits::negZero();
const T inf = FPBits::inf();
const T negInf = FPBits::negInf();
const T nan = FPBits::buildNaN(1);
static inline mpfr::RoundingMode toMPFRRoundingMode(int mode) {
switch (mode) {
case FE_UPWARD:
return mpfr::RoundingMode::Upward;
case FE_DOWNWARD:
return mpfr::RoundingMode::Downward;
case FE_TOWARDZERO:
return mpfr::RoundingMode::TowardZero;
case FE_TONEAREST:
return mpfr::RoundingMode::Nearest;
default:
__builtin_unreachable();
}
}
public:
void testSpecialNumbers(RIntFunc func) {
for (int mode : roundingModes) {
__llvm_libc::fputil::setRound(mode);
ASSERT_FP_EQ(inf, func(inf));
ASSERT_FP_EQ(negInf, func(negInf));
ASSERT_FP_EQ(nan, func(nan));
ASSERT_FP_EQ(zero, func(zero));
ASSERT_FP_EQ(negZero, func(negZero));
}
}
void testRoundNumbers(RIntFunc func) {
for (int mode : roundingModes) {
__llvm_libc::fputil::setRound(mode);
mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
ASSERT_FP_EQ(func(T(1.0)), mpfr::Round(T(1.0), mpfrMode));
ASSERT_FP_EQ(func(T(-1.0)), mpfr::Round(T(-1.0), mpfrMode));
ASSERT_FP_EQ(func(T(10.0)), mpfr::Round(T(10.0), mpfrMode));
ASSERT_FP_EQ(func(T(-10.0)), mpfr::Round(T(-10.0), mpfrMode));
ASSERT_FP_EQ(func(T(1234.0)), mpfr::Round(T(1234.0), mpfrMode));
ASSERT_FP_EQ(func(T(-1234.0)), mpfr::Round(T(-1234.0), mpfrMode));
}
}
void testFractions(RIntFunc func) {
for (int mode : roundingModes) {
__llvm_libc::fputil::setRound(mode);
mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
ASSERT_FP_EQ(func(T(0.5)), mpfr::Round(T(0.5), mpfrMode));
ASSERT_FP_EQ(func(T(-0.5)), mpfr::Round(T(-0.5), mpfrMode));
ASSERT_FP_EQ(func(T(0.115)), mpfr::Round(T(0.115), mpfrMode));
ASSERT_FP_EQ(func(T(-0.115)), mpfr::Round(T(-0.115), mpfrMode));
ASSERT_FP_EQ(func(T(0.715)), mpfr::Round(T(0.715), mpfrMode));
ASSERT_FP_EQ(func(T(-0.715)), mpfr::Round(T(-0.715), mpfrMode));
}
}
void testSubnormalRange(RIntFunc func) {
constexpr UIntType count = 1000001;
constexpr UIntType step =
(FPBits::maxSubnormal - FPBits::minSubnormal) / count;
for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
i += step) {
T x = FPBits(i);
for (int mode : roundingModes) {
__llvm_libc::fputil::setRound(mode);
mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
ASSERT_FP_EQ(func(x), mpfr::Round(x, mpfrMode));
}
}
}
void testNormalRange(RIntFunc func) {
constexpr UIntType count = 1000001;
constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
for (UIntType i = FPBits::minNormal; i <= FPBits::maxNormal; i += step) {
T x = FPBits(i);
// In normal range on x86 platforms, the long double implicit 1 bit can be
// zero making the numbers NaN. We will skip them.
if (isnan(x)) {
continue;
}
for (int mode : roundingModes) {
__llvm_libc::fputil::setRound(mode);
mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
ASSERT_FP_EQ(func(x), mpfr::Round(x, mpfrMode));
}
}
}
};
#define LIST_RINT_TESTS(F, func) \
using RIntTest = RIntTestTemplate<F>; \
TEST_F(RIntTest, specialNumbers) { testSpecialNumbers(&func); } \
TEST_F(RIntTest, RoundNumbers) { testRoundNumbers(&func); } \
TEST_F(RIntTest, Fractions) { testFractions(&func); } \
TEST_F(RIntTest, SubnormalRange) { testSubnormalRange(&func); } \
TEST_F(RIntTest, NormalRange) { testNormalRange(&func); }
#endif // LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H

View File

@ -10,9 +10,6 @@
#define LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
#include "src/errno/llvmlibc_errno.h"
#include "src/fenv/feclearexcept.h"
#include "src/fenv/feraiseexcept.h"
#include "src/fenv/fetestexcept.h"
#include "utils/FPUtil/FPBits.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
#include "utils/UnitTest/Test.h"
@ -27,7 +24,10 @@
namespace mpfr = __llvm_libc::testing::mpfr;
template <typename F, typename I>
static constexpr int roundingModes[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
FE_TONEAREST};
template <typename F, typename I, bool TestModes = false>
class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
public:
typedef I (*RoundToIntegerFunc)(F);
@ -50,21 +50,21 @@ private:
llvmlibc_errno = 0;
#endif
#if math_errhandling & MATH_ERREXCEPT
__llvm_libc::feclearexcept(FE_ALL_EXCEPT);
__llvm_libc::fputil::clearExcept(FE_ALL_EXCEPT);
#endif
ASSERT_EQ(func(input), expected);
if (expectError) {
#if math_errhandling & MATH_ERREXCEPT
ASSERT_EQ(__llvm_libc::fetestexcept(FE_ALL_EXCEPT), FE_INVALID);
ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT), FE_INVALID);
#endif
#if math_errhandling & MATH_ERRNO
ASSERT_EQ(llvmlibc_errno, EDOM);
#endif
} else {
#if math_errhandling & MATH_ERREXCEPT
ASSERT_EQ(__llvm_libc::fetestexcept(FE_ALL_EXCEPT), 0);
ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT), 0);
#endif
#if math_errhandling & MATH_ERRNO
ASSERT_EQ(llvmlibc_errno, 0);
@ -72,6 +72,21 @@ private:
}
}
static inline mpfr::RoundingMode toMPFRRoundingMode(int mode) {
switch (mode) {
case FE_UPWARD:
return mpfr::RoundingMode::Upward;
case FE_DOWNWARD:
return mpfr::RoundingMode::Downward;
case FE_TOWARDZERO:
return mpfr::RoundingMode::TowardZero;
case FE_TONEAREST:
return mpfr::RoundingMode::Nearest;
default:
__builtin_unreachable();
}
}
public:
void SetUp() override {
#if math_errhandling & MATH_ERREXCEPT
@ -82,13 +97,24 @@ public:
#endif
}
void testInfinityAndNaN(RoundToIntegerFunc func) {
void doInfinityAndNaNTest(RoundToIntegerFunc func) {
testOneInput(func, inf, IntegerMax, true);
testOneInput(func, negInf, IntegerMin, true);
testOneInput(func, nan, IntegerMax, true);
}
void testRoundNumbers(RoundToIntegerFunc func) {
void testInfinityAndNaN(RoundToIntegerFunc func) {
if (TestModes) {
for (int mode : roundingModes) {
__llvm_libc::fputil::setRound(mode);
doInfinityAndNaNTest(func);
}
} else {
doInfinityAndNaNTest(func);
}
}
void doRoundNumbersTest(RoundToIntegerFunc func) {
testOneInput(func, zero, I(0), false);
testOneInput(func, negZero, I(0), false);
testOneInput(func, F(1.0), I(1), false);
@ -121,13 +147,44 @@ public:
testOneInput(func, x, mpfrResult, false);
}
void testRoundNumbers(RoundToIntegerFunc func) {
if (TestModes) {
for (int mode : roundingModes) {
__llvm_libc::fputil::setRound(mode);
doRoundNumbersTest(func);
}
} else {
doRoundNumbersTest(func);
}
}
void doFractionsTest(RoundToIntegerFunc func, int mode) {
constexpr F fractions[] = {0.5, -0.5, 0.115, -0.115, 0.715, -0.715};
for (F x : fractions) {
long mpfrLongResult;
bool erangeflag;
if (TestModes)
erangeflag =
mpfr::RoundToLong(x, toMPFRRoundingMode(mode), mpfrLongResult);
else
erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
ASSERT_FALSE(erangeflag);
I mpfrResult = mpfrLongResult;
testOneInput(func, x, mpfrResult, false);
}
}
void testFractions(RoundToIntegerFunc func) {
testOneInput(func, F(0.5), I(1), false);
testOneInput(func, F(-0.5), I(-1), false);
testOneInput(func, F(0.115), I(0), false);
testOneInput(func, F(-0.115), I(0), false);
testOneInput(func, F(0.715), I(1), false);
testOneInput(func, F(-0.715), I(-1), false);
if (TestModes) {
for (int mode : roundingModes) {
__llvm_libc::fputil::setRound(mode);
doFractionsTest(func, mode);
}
} else {
// Passing 0 for mode has no effect as it is not used in doFractionsTest
// when `TestModes` is false;
doFractionsTest(func, 0);
}
}
void testIntegerOverflow(RoundToIntegerFunc func) {
@ -149,29 +206,56 @@ public:
<< (__llvm_libc::fputil::MantissaWidth<F>::value - 1);
F x = bits;
long mpfrResult;
bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
ASSERT_TRUE(erangeflag);
testOneInput(func, x, IntegerMin, true);
if (TestModes) {
for (int m : roundingModes) {
__llvm_libc::fputil::setRound(m);
long mpfrLongResult;
bool erangeflag =
mpfr::RoundToLong(x, toMPFRRoundingMode(m), mpfrLongResult);
ASSERT_TRUE(erangeflag);
testOneInput(func, x, IntegerMin, true);
}
} else {
long mpfrLongResult;
bool erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
ASSERT_TRUE(erangeflag);
testOneInput(func, x, IntegerMin, true);
}
}
void testSubnormalRange(RoundToIntegerFunc func) {
// This function compares with an equivalent MPFR function which rounds
// floating point numbers to long values. There is no MPFR function to
// round to long long or wider integer values. So, we will peform the
// comparisons in this function only if the width of I less than equal to
// that of long.
if (sizeof(I) > sizeof(long))
return;
constexpr UIntType count = 1000001;
constexpr UIntType step =
(FPBits::maxSubnormal - FPBits::minSubnormal) / count;
for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
i += step) {
F x = FPBits(i);
if (x == F(0.0))
continue;
// All subnormal numbers should round to zero.
testOneInput(func, x, 0L, false);
if (TestModes) {
if (x > 0) {
__llvm_libc::fputil::setRound(FE_UPWARD);
testOneInput(func, x, I(1), false);
__llvm_libc::fputil::setRound(FE_DOWNWARD);
testOneInput(func, x, I(0), false);
__llvm_libc::fputil::setRound(FE_TOWARDZERO);
testOneInput(func, x, I(0), false);
__llvm_libc::fputil::setRound(FE_TONEAREST);
testOneInput(func, x, I(0), false);
} else {
__llvm_libc::fputil::setRound(FE_UPWARD);
testOneInput(func, x, I(0), false);
__llvm_libc::fputil::setRound(FE_DOWNWARD);
testOneInput(func, x, I(-1), false);
__llvm_libc::fputil::setRound(FE_TOWARDZERO);
testOneInput(func, x, I(0), false);
__llvm_libc::fputil::setRound(FE_TONEAREST);
testOneInput(func, x, I(0), false);
}
} else {
testOneInput(func, x, 0L, false);
}
}
}
@ -194,18 +278,33 @@ public:
continue;
}
long mpfrResult;
bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
if (erangeflag)
testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
else
testOneInput(func, x, mpfrResult, false);
if (TestModes) {
for (int m : roundingModes) {
long mpfrLongResult;
bool erangeflag =
mpfr::RoundToLong(x, toMPFRRoundingMode(m), mpfrLongResult);
I mpfrResult = mpfrLongResult;
__llvm_libc::fputil::setRound(m);
if (erangeflag)
testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
else
testOneInput(func, x, mpfrResult, false);
}
} else {
long mpfrLongResult;
bool erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
I mpfrResult = mpfrLongResult;
if (erangeflag)
testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
else
testOneInput(func, x, mpfrResult, false);
}
}
}
};
#define LIST_ROUND_TO_INTEGER_TESTS(F, I, func) \
using RoundToIntegerTest = RoundToIntegerTestTemplate<F, I>; \
#define LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, TestModes) \
using RoundToIntegerTest = RoundToIntegerTestTemplate<F, I, TestModes>; \
TEST_F(RoundToIntegerTest, InfinityAndNaN) { testInfinityAndNaN(&func); } \
TEST_F(RoundToIntegerTest, RoundNumbers) { testRoundNumbers(&func); } \
TEST_F(RoundToIntegerTest, Fractions) { testFractions(&func); } \
@ -213,4 +312,10 @@ public:
TEST_F(RoundToIntegerTest, SubnormalRange) { testSubnormalRange(&func); } \
TEST_F(RoundToIntegerTest, NormalRange) { testNormalRange(&func); }
#define LIST_ROUND_TO_INTEGER_TESTS(F, I, func) \
LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, false)
#define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(F, I, func) \
LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, true)
#endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H

View File

@ -0,0 +1,13 @@
//===-- Unittests for llrint ----------------------------------------------===//
//
// 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 "RoundToIntegerTest.h"
#include "src/math/llrint.h"
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(double, long long, __llvm_libc::llrint)

View File

@ -0,0 +1,13 @@
//===-- Unittests for llrintf ---------------------------------------------===//
//
// 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 "RoundToIntegerTest.h"
#include "src/math/llrintf.h"
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(float, long long, __llvm_libc::llrintf)

View File

@ -0,0 +1,14 @@
//===-- Unittests for llrintl ---------------------------------------------===//
//
// 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 "RoundToIntegerTest.h"
#include "src/math/llrintl.h"
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(long double, long long,
__llvm_libc::llrintl)

View File

@ -0,0 +1,13 @@
//===-- Unittests for lrint -----------------------------------------------===//
//
// 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 "RoundToIntegerTest.h"
#include "src/math/lrint.h"
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(double, long, __llvm_libc::lrint)

View File

@ -0,0 +1,13 @@
//===-- Unittests for lrintf ----------------------------------------------===//
//
// 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 "RoundToIntegerTest.h"
#include "src/math/lrintf.h"
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(float, long, __llvm_libc::lrintf)

View File

@ -0,0 +1,13 @@
//===-- Unittests for lrintl ----------------------------------------------===//
//
// 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 "RoundToIntegerTest.h"
#include "src/math/lrintl.h"
LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(long double, long, __llvm_libc::lrintl)

View File

@ -0,0 +1,13 @@
//===-- Unittests for rint ------------------------------------------------===//
//
// 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 "RIntTest.h"
#include "src/math/rint.h"
LIST_RINT_TESTS(double, __llvm_libc::rint)

View File

@ -0,0 +1,13 @@
//===-- Unittests for rintf -----------------------------------------------===//
//
// 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 "RIntTest.h"
#include "src/math/rintf.h"
LIST_RINT_TESTS(float, __llvm_libc::rintf)

View File

@ -0,0 +1,13 @@
//===-- Unittests for rintl -----------------------------------------------===//
//
// 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 "RIntTest.h"
#include "src/math/rintl.h"
LIST_RINT_TESTS(long double, __llvm_libc::rintl)

View File

@ -9,14 +9,12 @@
#ifndef LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
#define LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H
#include "FEnv.h"
#include "FPBits.h"
#include "utils/CPP/TypeTraits.h"
#include <math.h>
#if math_errhandling & MATH_ERREXCEPT
#include "FEnv.h"
#endif
#if math_errhandling & MATH_ERRNO
#include "src/errno/llvmlibc_errno.h"
#include <errno.h>
@ -159,17 +157,94 @@ static inline T round(T x) {
}
}
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline T roundUsingCurrentRoundingMode(T x) {
using UIntType = typename FPBits<T>::UIntType;
FPBits<T> bits(x);
// If x is infinity NaN or zero, return it.
if (bits.isInfOrNaN() || bits.isZero())
return x;
bool isNeg = bits.sign;
int exponent = bits.getExponent();
int roundingMode = getRound();
// If the exponent is greater than the most negative mantissa
// exponent, then x is already an integer.
if (exponent >= static_cast<int>(MantissaWidth<T>::value))
return x;
if (exponent <= -1) {
switch (roundingMode) {
case FE_DOWNWARD:
return isNeg ? T(-1.0) : T(0.0);
case FE_UPWARD:
return isNeg ? T(-0.0) : T(1.0);
case FE_TOWARDZERO:
return isNeg ? T(-0.0) : T(0.0);
case FE_TONEAREST:
if (exponent <= -2 || bits.mantissa == 0)
return isNeg ? T(-0.0) : T(0.0); // abs(x) <= 0.5
else
return isNeg ? T(-1.0) : T(1.0); // abs(x) > 0.5
default:
__builtin_unreachable();
}
}
uint32_t trimSize = MantissaWidth<T>::value - exponent;
FPBits<T> newBits = bits;
newBits.mantissa = (bits.mantissa >> trimSize) << trimSize;
T truncValue = T(newBits);
// If x is already an integer, return it.
if (truncValue == x)
return x;
UIntType trimValue = bits.mantissa & ((UIntType(1) << trimSize) - 1);
UIntType halfValue = (UIntType(1) << (trimSize - 1));
// If exponent is 0, trimSize will be equal to the mantissa width, and
// truncIsOdd` will not be correct. So, we handle it as a special case
// below.
UIntType truncIsOdd = newBits.mantissa & (UIntType(1) << trimSize);
switch (roundingMode) {
case FE_DOWNWARD:
return isNeg ? truncValue - T(1.0) : truncValue;
case FE_UPWARD:
return isNeg ? truncValue : truncValue + T(1.0);
case FE_TOWARDZERO:
return truncValue;
case FE_TONEAREST:
if (trimValue > halfValue) {
return isNeg ? truncValue - T(1.0) : truncValue + T(1.0);
} else if (trimValue == halfValue) {
if (exponent == 0)
return isNeg ? T(-2.0) : T(2.0);
if (truncIsOdd)
return isNeg ? truncValue - T(1.0) : truncValue + T(1.0);
else
return truncValue;
} else {
return truncValue;
}
default:
__builtin_unreachable();
}
}
namespace internal {
template <typename F, typename I,
cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
cpp::IsIntegral<I>::Value,
int> = 0>
static inline I roundToSignedInteger(F x) {
static inline I roundedFloatToSignedInteger(F x) {
constexpr I IntegerMin = (I(1) << (sizeof(I) * 8 - 1));
constexpr I IntegerMax = -(IntegerMin + 1);
using FPBits = FPBits<F>;
F roundedValue = round(x);
FPBits bits(roundedValue);
FPBits<F> bits(x);
auto setDomainErrorAndRaiseInvalid = []() {
#if math_errhandling & MATH_ERRNO
llvmlibc_errno = EDOM;
@ -180,8 +255,6 @@ static inline I roundToSignedInteger(F x) {
};
if (bits.isInfOrNaN()) {
// Result of round is infinity or NaN only if x is infinity
// or NaN.
setDomainErrorAndRaiseInvalid();
return bits.sign ? IntegerMin : IntegerMax;
}
@ -200,10 +273,29 @@ static inline I roundToSignedInteger(F x) {
// value is the most negative number for the signed integer type I.
}
// For all other cases, if |roundedValue| can fit in the integer type |I|,
// we just return the roundedValue. Implicit conversion will convert the
// For all other cases, if `x` can fit in the integer type `I`,
// we just return `x`. Implicit conversion will convert the
// floating point value to the exact integer value.
return roundedValue;
return x;
}
} // namespace internal
template <typename F, typename I,
cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
cpp::IsIntegral<I>::Value,
int> = 0>
static inline I roundToSignedInteger(F x) {
return internal::roundedFloatToSignedInteger<F, I>(round(x));
}
template <typename F, typename I,
cpp::EnableIfType<cpp::IsFloatingPointType<F>::Value &&
cpp::IsIntegral<I>::Value,
int> = 0>
static inline I roundToSignedIntegerUsingCurrentRoundingMode(F x) {
return internal::roundedFloatToSignedInteger<F, I>(
roundUsingCurrentRoundingMode(x));
}
} // namespace fputil

View File

@ -163,6 +163,18 @@ public:
return mpfr_erangeflag_p();
}
bool roundToLong(mpfr_rnd_t rnd, long &result) const {
MPFRNumber rint_result;
mpfr_rint(rint_result.value, value, rnd);
return rint_result.roundToLong(result);
}
MPFRNumber rint(mpfr_rnd_t rnd) const {
MPFRNumber result;
mpfr_rint(result.value, value, rnd);
return result;
}
MPFRNumber sin() const {
MPFRNumber result;
mpfr_sin(result.value, value, MPFR_RNDN);
@ -563,6 +575,23 @@ compareBinaryOperationOneOutput<double>(Operation, const BinaryInput<double> &,
template bool compareBinaryOperationOneOutput<long double>(
Operation, const BinaryInput<long double> &, long double, double);
static mpfr_rnd_t getMPFRRoundingMode(RoundingMode mode) {
switch (mode) {
case RoundingMode::Upward:
return MPFR_RNDU;
break;
case RoundingMode::Downward:
return MPFR_RNDD;
break;
case RoundingMode::TowardZero:
return MPFR_RNDZ;
break;
case RoundingMode::Nearest:
return MPFR_RNDN;
break;
}
}
} // namespace internal
template <typename T> bool RoundToLong(T x, long &result) {
@ -574,6 +603,25 @@ template bool RoundToLong<float>(float, long &);
template bool RoundToLong<double>(double, long &);
template bool RoundToLong<long double>(long double, long &);
template <typename T> bool RoundToLong(T x, RoundingMode mode, long &result) {
MPFRNumber mpfr(x);
return mpfr.roundToLong(internal::getMPFRRoundingMode(mode), result);
}
template bool RoundToLong<float>(float, RoundingMode, long &);
template bool RoundToLong<double>(double, RoundingMode, long &);
template bool RoundToLong<long double>(long double, RoundingMode, long &);
template <typename T> T Round(T x, RoundingMode mode) {
MPFRNumber mpfr(x);
MPFRNumber result = mpfr.rint(internal::getMPFRRoundingMode(mode));
return result.as<T>();
}
template float Round<float>(float, RoundingMode);
template double Round<double>(double, RoundingMode);
template long double Round<long double>(long double, RoundingMode);
} // namespace mpfr
} // namespace testing
} // namespace __llvm_libc

View File

@ -237,7 +237,12 @@ getMPFRMatcher(InputType input, OutputType outputUnused, double t) {
return internal::MPFRMatcher<op, InputType, OutputType>(input, t);
}
enum class RoundingMode : uint8_t { Upward, Downward, TowardZero, Nearest };
template <typename T> T Round(T x, RoundingMode mode);
template <typename T> bool RoundToLong(T x, long &result);
template <typename T> bool RoundToLong(T x, RoundingMode mode, long &result);
} // namespace mpfr
} // namespace testing