From afe1c39f8aba65cbeb30b3008694a010319a0837 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 | 23 +- test/nearest/rint_test.cpp.in | 310 ++++++++++++++++++++++++ test/nearest/rint_test_compile_time.cpp | 123 ++++++++++ 4 files changed, 687 insertions(+), 1 deletion(-) create mode 100644 test/nearest/rint_test.cpp.in create mode 100644 test/nearest/rint_test_compile_time.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..ede7474 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -92,11 +92,32 @@ target_link_libraries(${PROJECT_NAME}-fmanip PRIVATE ) add_executable(${PROJECT_NAME}-nearest) +set(ROUNDING_MODES + FE_DOWNWARD + FE_UPWARD + FE_TONEAREST + FE_TOWARDZERO +) +set(GENERATED_SOURCES) +foreach(MODE IN LISTS ROUNDING_MODES) + # Set the output file name based on the rounding mode + string(REPLACE "FE_" "" MODE_SUFFIX ${MODE}) + set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/rounding_${MODE_SUFFIX}.cpp") + set(ROUNDING_MODE "FE_${MODE_SUFFIX}") + # Configure the template file to generate the specific cpp file + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/nearest/rint_test.cpp.in + ${OUTPUT_FILE} + @ONLY + ) + list(APPEND GENERATED_SOURCES ${OUTPUT_FILE}) +endforeach() target_sources(${PROJECT_NAME}-nearest PRIVATE nearest/floor_test.cpp nearest/nearbyint_test.cpp nearest/trunc_test.cpp - + nearest/rint_test_compile_time.cpp + ${GENERATED_SOURCES} ) target_link_libraries(${PROJECT_NAME}-nearest PRIVATE ccmath::test diff --git a/test/nearest/rint_test.cpp.in b/test/nearest/rint_test.cpp.in new file mode 100644 index 0000000..c724de0 --- /dev/null +++ b/test/nearest/rint_test.cpp.in @@ -0,0 +1,310 @@ +/* + * 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 + +#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 + +template +class CcmathRIntBaseTests_@ROUNDING_MODE@ : public TestWithParam +{ +protected: + CcmathRIntBaseTests_@ROUNDING_MODE@() { std::fesetround(@ROUNDING_MODE@); } +}; + +// ccm::rint, ccm::rintl, ccm::rintf +class CcmathRIntFloatTests_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +class CcmathRIntDoubleTests_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +class CcmathRIntLongDoubleTests_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +INSTANTIATE_TEST_SUITE_P(RIntFloatTests, CcmathRIntFloatTests_@ROUNDING_MODE@, ValuesIn(createTestParams(kFloatTestParams, std::rint))); +INSTANTIATE_TEST_SUITE_P(RIntDoubleTests, CcmathRIntDoubleTests_@ROUNDING_MODE@, ValuesIn(createTestParams(kDoubleTestParams, std::rint))); +INSTANTIATE_TEST_SUITE_P(RIntLongDoubleTests, CcmathRIntLongDoubleTests_@ROUNDING_MODE@, ValuesIn(createTestParams(kLongDoubleTestParams, std::rint))); + +TEST_P(CcmathRIntFloatTests_@ROUNDING_MODE@, 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_@ROUNDING_MODE@, 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_@ROUNDING_MODE@, 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_@ROUNDING_MODE@, 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_@ROUNDING_MODE@, 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_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +class CcmathLRIntDoubleTests_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +class CcmathLRIntLongDoubleTests_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +INSTANTIATE_TEST_SUITE_P(LRIntFloatTests, CcmathLRIntFloatTests_@ROUNDING_MODE@, ValuesIn(createTestParams(kFloatTestParams, std::lrint))); +INSTANTIATE_TEST_SUITE_P(LRIntDoubleTests, CcmathLRIntDoubleTests_@ROUNDING_MODE@, ValuesIn(createTestParams(kDoubleTestParams, std::lrint))); +INSTANTIATE_TEST_SUITE_P(LRIntLongDoubleTests, CcmathLRIntLongDoubleTests_@ROUNDING_MODE@, ValuesIn(createTestParams(kLongDoubleTestParams, std::lrint))); + +TEST_P(CcmathLRIntFloatTests_@ROUNDING_MODE@, LRIntFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLRIntFloatTests_@ROUNDING_MODE@, LRIntFFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrintf(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLRIntDoubleTests_@ROUNDING_MODE@, LRIntDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLRIntLongDoubleTests_@ROUNDING_MODE@, LRIntLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::lrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLRIntLongDoubleTests_@ROUNDING_MODE@, 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_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +class CcmathLLRIntDoubleTests_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +class CcmathLLRIntLongDoubleTests_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +}; + +INSTANTIATE_TEST_SUITE_P(LLRIntFloatTests, CcmathLLRIntFloatTests_@ROUNDING_MODE@, ValuesIn(createTestParams(kFloatTestParams, std::llrint))); +INSTANTIATE_TEST_SUITE_P(LLRIntDoubleTests, CcmathLLRIntDoubleTests_@ROUNDING_MODE@, ValuesIn(createTestParams(kDoubleTestParams, std::llrint))); +INSTANTIATE_TEST_SUITE_P(LLRIntLongDoubleTests, CcmathLLRIntLongDoubleTests_@ROUNDING_MODE@, + ValuesIn(createTestParams(kLongDoubleTestParams, std::llrint))); + +TEST_P(CcmathLLRIntFloatTests_@ROUNDING_MODE@, LLRIntFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLLRIntFloatTests_@ROUNDING_MODE@, LLRIntFFloat) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrintf(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLLRIntDoubleTests_@ROUNDING_MODE@, LLRIntDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLLRIntLongDoubleTests_@ROUNDING_MODE@, LLRIntLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrint(params.input)}; + EXPECT_EQ(params.output, actual); +} + +TEST_P(CcmathLLRIntLongDoubleTests_@ROUNDING_MODE@, LLRIntLLongDouble) +{ + const auto & params{GetParam()}; + const auto actual{ccm::llrintl(params.input)}; + EXPECT_EQ(params.output, actual); +} + +// FE_INVALID raised tests +class RIntRaisesFE_INVALIDTests_@ROUNDING_MODE@ : public CcmathRIntBaseTests_@ROUNDING_MODE@> +{ +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_@ROUNDING_MODE@, ValuesIn(kValuesThatWilRaisedFE_INVALID)); + +TEST_P(RIntRaisesFE_INVALIDTests_@ROUNDING_MODE@, FE_INVALIDIsRaised) +{ + GetParam()(); + EXPECT_TRUE(std::fetestexcept(FE_INVALID)); +} diff --git a/test/nearest/rint_test_compile_time.cpp b/test/nearest/rint_test_compile_time.cpp new file mode 100644 index 0000000..c407ed1 --- /dev/null +++ b/test/nearest/rint_test_compile_time.cpp @@ -0,0 +1,123 @@ +/* + * 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 + +#include + +// Disabling test case ccm::nearbyintl if run on clang linux. +#ifdef __clang__ + #ifdef __linux__ + #define CLANG_LINUX + #endif +#endif + +// Compile Time Tests + +#ifndef CLANG_LINUX +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); +} +#endif + +// Remove #define CLANG_LINUX +#ifdef CLANG_LINUX + #undef CLANG_LINUX +#endif