From a19e9e7270719828bb8e3a16b7fe3cda5e81271a Mon Sep 17 00:00:00 2001 From: Kyle Hurd Date: Sat, 24 Aug 2024 04:43:53 -0400 Subject: [PATCH] Implements rint Functions implemented: - ccm::rint(float) - ccm::rint(double) - ccm::rint(long double) - ccm::rintl(long double) - ccm::rintf(float) - ccm::lrint(float) - ccm::lrint(double) - ccm::lrint(long double) - ccm::lrintl(long double) - ccm::lrintf(float) - ccm::llrint(float) - ccm::llrint(double) - ccm::llrint(long double) - ccm::llrintl(long double) - ccm::llrintf(long double) Tests written for: - Common and edge case conditions for `float`, `double`, and `long double` inputs. - Assert that FE_INVALID is raised for +/- infinity values and NaN values. - Asserts that functions can be evaluated at compile time. --- include/ccmath/math/nearest/rint.hpp | 232 ++++++++++++++++ test/CMakeLists.txt | 1 + test/nearest/rint_test.cpp | 393 +++++++++++++++++++++++++++ 3 files changed, 626 insertions(+) create mode 100644 test/nearest/rint_test.cpp diff --git a/include/ccmath/math/nearest/rint.hpp b/include/ccmath/math/nearest/rint.hpp index 4b94f7d..c58de97 100644 --- a/include/ccmath/math/nearest/rint.hpp +++ b/include/ccmath/math/nearest/rint.hpp @@ -10,7 +10,239 @@ #pragma once +#include +#include +#include +#include +#include +#include + namespace ccm { + /** + * @brief Rounds the floating-point argument num to an integer value (in floating-point format), using the current rounding mode. The library provides + * overloads of std::rint for all cv-unqualified floating-point types as the type of the parameter num. + * @tparam T The type of the number. + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + template , bool> = true> + constexpr T rint(T num) + { + if (ccm::isinf(num) || ccm::isnan(num)) { ccm::support::fenv::raise_except_if_required(FE_INVALID); } + constexpr auto rounding_mode{ccm::support::fenv::get_rounding_mode()}; + return ccm::support::fp::directional_round(num, rounding_mode); + } + + /** + * @brief Additional overloads are provided for all integer types, which are treated as double. + * @tparam Integer The type of the integral value. + * @param num An integral value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + template , bool> = true> + constexpr double rint(Integer num) + { + return static_cast(num); + } + + /** + * @brief Additional overloads are provided for all integer types, which are treated as double. + * @tparam Integer The type of the integral value. + * @param num An integral value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + template , bool> = true> + constexpr long lrint(Integer num) + { + return static_cast(num); + } + + /** + * @brief Additional overloads are provided for all integer types, which are treated as double. + * @tparam Integer The type of the integral value. + * @param num An integral value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + template , bool> = true> + constexpr long long llrint(Integer num) + { + return static_cast(num); + } + + /** + * @brief Rounds the floating-point argument num to an integer value (in floating-point format), using the current rounding mode. The library provides + * overloads of std::rint for all cv-unqualified floating-point types as the type of the parameter num. + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr float rint(float num) + { + return ccm::rint(num); + } + + /** + * @brief Rounds the floating-point argument num to an integer value (in floating-point format), using the current rounding mode. The library provides + * overloads of std::rint for all cv-unqualified floating-point types as the type of the parameter num. + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr double rint(double num) + { + return ccm::rint(num); + } + + /** + * @brief Rounds the floating-point argument num to an integer value (in floating-point format), using the current rounding mode. The library provides + * overloads of std::rint for all cv-unqualified floating-point types as the type of the parameter num. + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long double rint(long double num) + { + return ccm::rint(num); + } + + /** + * @brief Rounds the floating-point argument num to an integer value (in floating-point format), using the current rounding mode. The library provides + * overloads of std::rint for all cv-unqualified floating-point types as the type of the parameter num. + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr float rintf(float num) + { + return ccm::rint(num); + } + + /** + * @brief Rounds the floating-point argument num to an integer value (in floating-point format), using the current rounding mode. The library provides + * overloads of std::rint for all cv-unqualified floating-point types as the type of the parameter num. + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long double rintl(long double num) + { + return ccm::rint(num); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long lrint(float num) + { + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long lrint(double num) + { + if (ccm::isnan(num)) + { + ccm::support::fenv::raise_except_if_required(FE_INVALID); + return std::numeric_limits::min(); + } + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long lrint(long double num) + { + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long lrintf(float num) + { + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long lrintl(long double num) + { + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long long llrint(float num) + { + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long long llrint(double num) + { + if (ccm::isnan(num)) + { + ccm::support::fenv::raise_except_if_required(FE_INVALID); + return std::numeric_limits::min(); + } + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long long llrint(long double num) + { + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long long llrintf(float num) + { + return static_cast(ccm::rint(num)); + } + + /** + * @brief Rounds the floating-point argument num to an integer value, using the current rounding mode. The library provides overloads of std::lrint and + * std::llrint for all cv-unqualified floating-point types as the type of the parameter num.( + * @param num A floating-point value. + * @return If no errors occur, the nearest integer value to num, according to the current rounding mode, is returned. + */ + constexpr long long llrintl(long double num) + { + return static_cast(ccm::rint(num)); + } } // namespace ccm diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7b87b95..56a5668 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -95,6 +95,7 @@ add_executable(${PROJECT_NAME}-nearest) target_sources(${PROJECT_NAME}-nearest PRIVATE nearest/floor_test.cpp nearest/nearbyint_test.cpp + nearest/rint_test.cpp nearest/trunc_test.cpp ) diff --git a/test/nearest/rint_test.cpp b/test/nearest/rint_test.cpp new file mode 100644 index 0000000..5e55e1a --- /dev/null +++ b/test/nearest/rint_test.cpp @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2024-Present Ian Pike + * Copyright (c) 2024-Present ccmath contributors + * + * This library is provided under the MIT License. + * See LICENSE for more information. + */ + +#include + +#include +#include +#include +#include + +#include + +namespace +{ + using testing::TestWithParam; + using testing::ValuesIn; + + template + struct RIntTestParams + { + InputType input{}; + OutputType output{}; + }; + + template + std::vector makeTestParams() + { + return std::vector{ + static_cast(-0.0), + static_cast(-0.5), + static_cast(-1.0), + static_cast(-1.5), + static_cast(-1.999), + static_cast(-2.001), + static_cast(-123.0), + static_cast(0.0), + static_cast(0.5), + static_cast(1.0), + static_cast(1.5), + static_cast(1.999), + static_cast(2.001), + static_cast(123.0), + std::numeric_limits::max(), + std::numeric_limits::infinity(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::denorm_min(), + -std::numeric_limits::max(), + -std::numeric_limits::infinity(), + }; + } + + // All of the function calls that raise FE_INVALID. + // clang-format off + const std::vector> kValuesThatWilRaisedFE_INVALID{ + [] { return ccm::rint(std::numeric_limits::infinity()); }, + [] { return ccm::rint(-std::numeric_limits::infinity()); }, + [] { return ccm::rint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::rint(std::numeric_limits::infinity()); }, + [] { return ccm::rint(-std::numeric_limits::infinity()); }, + [] { return ccm::rint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::rintf(std::numeric_limits::infinity()); }, + [] { return ccm::rintf(-std::numeric_limits::infinity()); }, + [] { return ccm::rintf(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::rint(std::numeric_limits::infinity()); }, + [] { return ccm::rint(-std::numeric_limits::infinity()); }, + [] { return ccm::rint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::rintl(std::numeric_limits::infinity()); }, + [] { return ccm::rintl(-std::numeric_limits::infinity()); }, + [] { return ccm::rintl(std::numeric_limits::quiet_NaN()); }, + + [] { return ccm::lrint(std::numeric_limits::infinity()); }, + [] { return ccm::lrint(-std::numeric_limits::infinity()); }, + [] { return ccm::lrint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::lrint(std::numeric_limits::infinity()); }, + [] { return ccm::lrint(-std::numeric_limits::infinity()); }, + [] { return ccm::lrint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::lrintf(std::numeric_limits::infinity()); }, + [] { return ccm::lrintf(-std::numeric_limits::infinity()); }, + [] { return ccm::lrintf(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::lrint(std::numeric_limits::infinity()); }, + [] { return ccm::lrint(-std::numeric_limits::infinity()); }, + [] { return ccm::lrint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::lrintl(std::numeric_limits::infinity()); }, + [] { return ccm::lrintl(-std::numeric_limits::infinity()); }, + [] { return ccm::lrintl(std::numeric_limits::quiet_NaN()); }, + + [] { return ccm::llrint(std::numeric_limits::infinity()); }, + [] { return ccm::llrint(-std::numeric_limits::infinity()); }, + [] { return ccm::llrint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::llrint(std::numeric_limits::infinity()); }, + [] { return ccm::llrint(-std::numeric_limits::infinity()); }, + [] { return ccm::llrint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::llrintf(std::numeric_limits::infinity()); }, + [] { return ccm::llrintf(-std::numeric_limits::infinity()); }, + [] { return ccm::llrintf(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::llrint(std::numeric_limits::infinity()); }, + [] { return ccm::llrint(-std::numeric_limits::infinity()); }, + [] { return ccm::llrint(std::numeric_limits::quiet_NaN()); }, + [] { return ccm::llrintl(std::numeric_limits::infinity()); }, + [] { return ccm::llrintl(-std::numeric_limits::infinity()); }, + [] { return ccm::llrintl(std::numeric_limits::quiet_NaN()); }, + }; + // clang-format on + + const std::vector kFloatTestParams{makeTestParams()}; + const std::vector kDoubleTestParams{makeTestParams()}; + const std::vector kLongDoubleTestParams{makeTestParams()}; + + template + auto createTestParams(const std::vector & inputValues, OutputType (*func)(InputType)) + { + std::vector> result; + std::transform(inputValues.cbegin(), inputValues.cend(), std::back_inserter(result), + [func](InputType value) { return RIntTestParams{value, func(value)}; }); + return result; + } + +} // namespace + +// ccm::rint, ccm::rintl, ccm::rintf +class CcmathRIntFloatTests : public TestWithParam> +{ +}; + +class CcmathRIntDoubleTests : public TestWithParam> +{ +}; + +class CcmathRIntLongDoubleTests : public TestWithParam> +{ +}; + +INSTANTIATE_TEST_SUITE_P(RIntFloatTests, CcmathRIntFloatTests, ValuesIn(createTestParams(kFloatTestParams, std::rint))); +INSTANTIATE_TEST_SUITE_P(RIntDoubleTests, CcmathRIntDoubleTests, ValuesIn(createTestParams(kDoubleTestParams, std::rint))); +INSTANTIATE_TEST_SUITE_P(RIntLongDoubleTests, CcmathRIntLongDoubleTests, ValuesIn(createTestParams(kLongDoubleTestParams, std::rint))); + +TEST_P(CcmathRIntFloatTests, RIntFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::rint(params.input)}; + if (std::isnan(params.input)) { EXPECT_TRUE(std::isnan(actual)); } + else { EXPECT_EQ(params.output, actual); } +} + +TEST_P(CcmathRIntFloatTests, RIntFFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::rintf(params.input)}; + if (std::isnan(params.input)) { EXPECT_TRUE(std::isnan(actual)); } + else { EXPECT_EQ(params.output, actual); } +} + +TEST_P(CcmathRIntDoubleTests, RIntDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::rint(params.input)}; + if (std::isnan(params.input)) { EXPECT_TRUE(std::isnan(actual)); } + else { EXPECT_EQ(params.output, actual); } +} + +TEST_P(CcmathRIntLongDoubleTests, RIntLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::rint(params.input)}; + if (std::isnan(params.input)) { EXPECT_TRUE(std::isnan(actual)); } + else { EXPECT_EQ(params.output, actual); } +} + +TEST_P(CcmathRIntLongDoubleTests, RIntLLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::rintl(params.input)}; + if (std::isnan(params.input)) { EXPECT_TRUE(std::isnan(actual)); } + else { EXPECT_EQ(params.output, actual); } +} + +// ccm::lrint, ccm::lrintf, ccm::lrintl +class CcmathLRIntFloatTests : public TestWithParam> +{ +}; + +class CcmathLRIntDoubleTests : public TestWithParam> +{ +}; + +class CcmathLRIntLongDoubleTests : public TestWithParam> +{ +}; + +INSTANTIATE_TEST_SUITE_P(LRIntFloatTests, CcmathLRIntFloatTests, ValuesIn(createTestParams(kFloatTestParams, std::lrint))); +INSTANTIATE_TEST_SUITE_P(LRIntDoubleTests, CcmathLRIntDoubleTests, ValuesIn(createTestParams(kDoubleTestParams, std::lrint))); +INSTANTIATE_TEST_SUITE_P(LRIntLongDoubleTests, CcmathLRIntLongDoubleTests, ValuesIn(createTestParams(kLongDoubleTestParams, std::lrint))); + +TEST_P(CcmathLRIntFloatTests, LRIntFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLRIntFloatTests, LRIntFFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrintf(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLRIntDoubleTests, LRIntDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLRIntLongDoubleTests, LRIntLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLRIntLongDoubleTests, LRIntLLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrintl(params.input)}; + EXPECT_EQ(params.output, actual); +} + +// ccm::llrint, ccm::llrintf, ccm::llrintl +class CcmathLLRIntFloatTests : public TestWithParam> +{ +}; + +class CcmathLLRIntDoubleTests : public TestWithParam> +{ +}; + +class CcmathLLRIntLongDoubleTests : public TestWithParam> +{ +}; + +INSTANTIATE_TEST_SUITE_P(LLRIntFloatTests, CcmathLLRIntFloatTests, ValuesIn(createTestParams(kFloatTestParams, std::llrint))); +INSTANTIATE_TEST_SUITE_P(LLRIntDoubleTests, CcmathLLRIntDoubleTests, ValuesIn(createTestParams(kDoubleTestParams, std::llrint))); +INSTANTIATE_TEST_SUITE_P(LLRIntLongDoubleTests, CcmathLLRIntLongDoubleTests, + ValuesIn(createTestParams(kLongDoubleTestParams, std::llrint))); + +TEST_P(CcmathLLRIntFloatTests, LLRIntFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLLRIntFloatTests, LLRIntFFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrintf(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLLRIntDoubleTests, LLRIntDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLLRIntLongDoubleTests, LLRIntLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLLRIntLongDoubleTests, LLRIntLLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrintl(params.input)}; + EXPECT_EQ(params.output, actual); +} + +// FE_INVALID raised tests +class RIntRaisesFE_INVALIDTests : public TestWithParam> +{ +protected: + void SetUp() override { std::feclearexcept(FE_ALL_EXCEPT); } + + void TearDown() override { std::feclearexcept(FE_ALL_EXCEPT); } +}; + +INSTANTIATE_TEST_SUITE_P(FE_INVALIDRaisedTests, RIntRaisesFE_INVALIDTests, ValuesIn(kValuesThatWilRaisedFE_INVALID)); + +TEST_P(RIntRaisesFE_INVALIDTests, FE_INVALIDIsRaised) +{ + GetParam()(); + EXPECT_TRUE(std::fetestexcept(FE_INVALID)); +} + +// Compile Time Tests +TEST(CcmathNearestTests, CcmRIntDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::rint(1.0)}; + static_assert(rint == 1.0); +} + +TEST(CcmathNearestTests, CcmRIntFloatCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::rint(1.0f)}; + static_assert(rint == 1.0f); +} + +TEST(CcmathNearestTests, CcmRIntFFloatCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::rintf(1.0f)}; + static_assert(rint == 1.0f); +} + +TEST(CcmathNearestTests, CcmRIntLongDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::rint(1.0l)}; + static_assert(rint == 1.0l); +} + +TEST(CcmathNearestTests, CcmRIntLLongDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::rintl(1.0l)}; + static_assert(rint == 1.0l); +} + +TEST(CcmathNearestTests, CcmLRIntDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::lrint(1.0)}; + static_assert(rint == 1.0); +} + +TEST(CcmathNearestTests, CcmLRIntFloatCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::lrint(1.0f)}; + static_assert(rint == 1.0f); +} + +TEST(CcmathNearestTests, CcmLRIntFFloatCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::lrintf(1.0f)}; + static_assert(rint == 1.0f); +} + +TEST(CcmathNearestTests, CcmLRIntLongDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::lrint(1.0l)}; + static_assert(rint == 1.0l); +} + +TEST(CcmathNearestTests, CcmLRIntLLongDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::lrintl(1.0l)}; + static_assert(rint == 1.0l); +} + +TEST(CcmathNearestTests, CcmLLRIntDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::llrint(1.0)}; + static_assert(rint == 1.0); +} + +TEST(CcmathNearestTests, CcmLLRIntFloatCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::llrint(1.0f)}; + static_assert(rint == 1.0f); +} + +TEST(CcmathNearestTests, CcmLLRIntFFloatCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::llrintf(1.0f)}; + static_assert(rint == 1.0f); +} + +TEST(CcmathNearestTests, CcmLLRIntLongDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::llrint(1.0l)}; + static_assert(rint == 1.0l); +} + +TEST(CcmathNearestTests, CcmLLRIntLLongDoubleCanBeEvaluatedAtCompileTime) +{ + constexpr auto rint{ccm::llrintl(1.0l)}; + static_assert(rint == 1.0l); +}