From e210aa8a022c489919cbc38fdbe342ca224b49e8 Mon Sep 17 00:00:00 2001 From: Joel Falcou Date: Fri, 8 Dec 2023 19:00:18 +0100 Subject: [PATCH] Fix bad interaction with /fp:fast --- include/tts/engine/precision.hpp | 25 +++++++++++++++------ include/tts/test/ranges.hpp | 10 ++++----- standalone/tts/tts.hpp | 32 ++++++++++++++++++--------- test/generator.cpp | 38 ++++++++++++++++---------------- test/precision/absolute.cpp | 23 ++++++++++--------- test/precision/ieee.cpp | 2 ++ test/precision/relative.cpp | 23 ++++++++++--------- test/precision/ulp.cpp | 8 ++++--- 8 files changed, 96 insertions(+), 65 deletions(-) diff --git a/include/tts/engine/precision.hpp b/include/tts/engine/precision.hpp index 4dfdfe5..3c06dcd 100644 --- a/include/tts/engine/precision.hpp +++ b/include/tts/engine/precision.hpp @@ -12,8 +12,19 @@ #include #include + namespace tts { +namespace detail +{ + #if defined(__FAST_MATH__) + inline constexpr auto isinf = [](auto) { return false; }; + inline constexpr auto isnan = [](auto) { return false; }; + #else + inline constexpr auto isinf = [](auto x) { return std::isinf(x); }; + inline constexpr auto isnan = [](auto x) { return std::isnan(x); }; + #endif +} //==================================================================================================================== /*! @brief Compute the absolute distance between two values @@ -35,9 +46,9 @@ namespace tts } else if constexpr(std::is_floating_point_v) // IEEE cases { - if((a == b) || (std::isnan(a) && std::isnan(b))) return 0.; + if((a == b) || (detail::isnan(a) && detail::isnan(b))) return 0.; - if(std::isinf(a) || std::isinf(b) || std::isnan(a) || std::isnan(b)) + if(detail::isinf(a) || detail::isinf(b) || detail::isnan(a) || detail::isnan(b)) return std::numeric_limits::infinity(); return std::abs(a - b); @@ -81,9 +92,9 @@ namespace tts { return a == b ? 0. : 100.; } else if constexpr(std::is_floating_point_v) // IEEE cases { - if((a == b) || (std::isnan(a) && std::isnan(b))) return 0.; + if((a == b) || (detail::isnan(a) && detail::isnan(b))) return 0.; - if(std::isinf(a) || std::isinf(b) || std::isnan(a) || std::isnan(b)) + if(detail::isinf(a) || detail::isinf(b) || detail::isnan(a) || detail::isnan(b)) return std::numeric_limits::infinity(); return 100. * (std::abs(a - b) / std::max(T(1), std::max(std::abs(a), std::abs(b)))); @@ -131,7 +142,7 @@ namespace tts { using ui_t = std::conditional_t, std::uint32_t, std::uint64_t>; - if((a == b) || (std::isnan(a) && std::isnan(b))) + if((a == b) || (detail::isnan(a) && detail::isnan(b))) { return 0.; } @@ -183,14 +194,14 @@ namespace tts @param a Value to compare @param b Value to compare - @return Is `a == b` or `std::isnan(a) && std::isnan(b)` + @return Is `a == b` or `detail::isnan(a) && detail::isnan(b)` **/ //==================================================================================================================== template inline bool is_ieee_equal(T const &a, U const &b) { if constexpr(std::is_floating_point_v) // IEEE cases { - return (a==b) || (std::isnan(a) && std::isnan(b)); + return (a==b) || (detail::isnan(a) && detail::isnan(b)); } else { diff --git a/include/tts/test/ranges.hpp b/include/tts/test/ranges.hpp index 74dd172..ea13ccb 100644 --- a/include/tts/test/ranges.hpp +++ b/include/tts/test/ranges.hpp @@ -112,11 +112,11 @@ namespace tts::detail inline std::size_t last_bucket_less(std::size_t nb_buckets, double ulp) noexcept { std::size_t bucket; - if (ulp <= 1.5 ) bucket = static_cast(std::ceil(ulp*2)); - else if(std::isinf(ulp)) bucket = nb_buckets-1; - else bucket = std::min( nb_buckets-2 - , static_cast(std::log2(next2(ulp))+4) - ); + if (ulp <= 1.5 ) bucket = static_cast(std::ceil(ulp*2)); + else if(detail::isinf(ulp)) bucket = nb_buckets-1; + else bucket = std::min ( nb_buckets-2 + , static_cast(std::log2(next2(ulp))+4) + ); return bucket; } diff --git a/standalone/tts/tts.hpp b/standalone/tts/tts.hpp index 8ce1c37..9417235 100644 --- a/standalone/tts/tts.hpp +++ b/standalone/tts/tts.hpp @@ -1340,6 +1340,16 @@ namespace tts::detail #include namespace tts { +namespace detail +{ + #if defined(__FAST_MATH__) + inline constexpr auto isinf = [](auto) { return false; }; + inline constexpr auto isnan = [](auto) { return false; }; + #else + inline constexpr auto isinf = [](auto x) { return std::isinf(x); }; + inline constexpr auto isnan = [](auto x) { return std::isnan(x); }; + #endif +} template inline double absolute_distance(T const &a, U const &b) { if constexpr(std::is_same_v) @@ -1350,8 +1360,8 @@ namespace tts } else if constexpr(std::is_floating_point_v) { - if((a == b) || (std::isnan(a) && std::isnan(b))) return 0.; - if(std::isinf(a) || std::isinf(b) || std::isnan(a) || std::isnan(b)) + if((a == b) || (detail::isnan(a) && detail::isnan(b))) return 0.; + if(detail::isinf(a) || detail::isinf(b) || detail::isnan(a) || detail::isnan(b)) return std::numeric_limits::infinity(); return std::abs(a - b); } @@ -1382,8 +1392,8 @@ namespace tts { return a == b ? 0. : 100.; } else if constexpr(std::is_floating_point_v) { - if((a == b) || (std::isnan(a) && std::isnan(b))) return 0.; - if(std::isinf(a) || std::isinf(b) || std::isnan(a) || std::isnan(b)) + if((a == b) || (detail::isnan(a) && detail::isnan(b))) return 0.; + if(detail::isinf(a) || detail::isinf(b) || detail::isnan(a) || detail::isnan(b)) return std::numeric_limits::infinity(); return 100. * (std::abs(a - b) / std::max(T(1), std::max(std::abs(a), std::abs(b)))); } @@ -1417,7 +1427,7 @@ namespace tts else if constexpr(std::is_floating_point_v) { using ui_t = std::conditional_t, std::uint32_t, std::uint64_t>; - if((a == b) || (std::isnan(a) && std::isnan(b))) + if((a == b) || (detail::isnan(a) && detail::isnan(b))) { return 0.; } @@ -1458,7 +1468,7 @@ namespace tts { if constexpr(std::is_floating_point_v) { - return (a==b) || (std::isnan(a) && std::isnan(b)); + return (a==b) || (detail::isnan(a) && detail::isnan(b)); } else { @@ -1596,11 +1606,11 @@ namespace tts::detail inline std::size_t last_bucket_less(std::size_t nb_buckets, double ulp) noexcept { std::size_t bucket; - if (ulp <= 1.5 ) bucket = static_cast(std::ceil(ulp*2)); - else if(std::isinf(ulp)) bucket = nb_buckets-1; - else bucket = std::min( nb_buckets-2 - , static_cast(std::log2(next2(ulp))+4) - ); + if (ulp <= 1.5 ) bucket = static_cast(std::ceil(ulp*2)); + else if(detail::isinf(ulp)) bucket = nb_buckets-1; + else bucket = std::min ( nb_buckets-2 + , static_cast(std::log2(next2(ulp))+4) + ); return bucket; } template diff --git a/test/generator.cpp b/test/generator.cpp index 5b9bdc5..5bfc511 100644 --- a/test/generator.cpp +++ b/test/generator.cpp @@ -14,7 +14,7 @@ template struct array_of template struct make; template struct make> { - using type = tts::types...>; + using type = tts::types...>; }; using types_list = typename make::type; @@ -69,7 +69,7 @@ TTS_CASE_WITH ( "Check behavior for non-scalar types" , ::tts::generate ( tts::value{37} , tts::ramp{65}, tts::ramp{1,2} , tts::reverse_ramp{10}, tts::reverse_ramp{100,2} - , tts::between{0,100} + , tts::between{0,128} , tts::randoms{0.,100.} , tts::sample{ std::uniform_real_distribution{0.,10.} } ) @@ -82,31 +82,30 @@ TTS_CASE_WITH ( "Check behavior for non-scalar types" , auto const& urng ) { - T value_ref { 37, 37, 37, 37, 37, 37, 37, 37, 37, 37} - , rmp_ref { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74} - , rmps_ref { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19} - , rrmp_ref { 19, 18, 17, 16, 15, 14, 13, 12, 11, 10} - , rrmps_ref {118,116,114,112,110,108,106,104,102,100}; + T value_ref { 37, 37, 37, 37, 37, 37, 37, 37, 37} + , rmp_ref { 65, 66, 67, 68, 69, 70, 71, 72, 73} + , rmps_ref { 1, 3, 5, 7, 9, 11, 13, 15, 17} + , rrmp_ref { 18, 17, 16, 15, 14, 13, 12, 11, 10} + , rrmps_ref {116,114,112,110,108,106,104,102,100}; using v_t = typename T::value_type; auto w1 = static_cast(0); - auto w2 = static_cast(100); - auto step = (w2-w1)/9; - + auto w2 = static_cast(128); + auto step = (w2-w1)/8; T btw_ref; for(std::size_t i=0;i(w1 + i*step), w2); } - TTS_EXPR_IS(value , (std::array const&) ); - TTS_EXPR_IS(rmp , (std::array const&) ); - TTS_EXPR_IS(rmps , (std::array const&) ); - TTS_EXPR_IS(rrmp , (std::array const&) ); - TTS_EXPR_IS(rrmps , (std::array const&) ); - TTS_EXPR_IS(btw , (std::array const&) ); - TTS_EXPR_IS(rng , (std::array const&) ); - TTS_EXPR_IS(urng , (std::array const&) ); + TTS_EXPR_IS(value , (std::array const&) ); + TTS_EXPR_IS(rmp , (std::array const&) ); + TTS_EXPR_IS(rmps , (std::array const&) ); + TTS_EXPR_IS(rrmp , (std::array const&) ); + TTS_EXPR_IS(rrmps , (std::array const&) ); + TTS_EXPR_IS(btw , (std::array const&) ); + TTS_EXPR_IS(rng , (std::array const&) ); + TTS_EXPR_IS(urng , (std::array const&) ); TTS_ALL_EQUAL(value , value_ref ); TTS_ALL_EQUAL(rmp , rmp_ref ); @@ -117,10 +116,11 @@ TTS_CASE_WITH ( "Check behavior for non-scalar types" for(auto e : rng) { - std::cout << "e: " << +e << "\n"; + std::cout << "e: " << +e << " "; TTS_GREATER_EQUAL(e, v_t(0)); TTS_LESS_EQUAL(e, v_t(100)); } + std::cout << std::endl; for(auto e : urng) { diff --git a/test/precision/absolute.cpp b/test/precision/absolute.cpp index ae7b1ad..e0d4b2a 100644 --- a/test/precision/absolute.cpp +++ b/test/precision/absolute.cpp @@ -19,11 +19,22 @@ TTS_CASE_TPL( "Absolute distance between floating point" (::tts::type) { T a{1}; + + TTS_ABSOLUTE_EQUAL(a , a , 0. ); + TTS_ABSOLUTE_EQUAL(a, a + 0.049f, .05 ); + TTS_ABSOLUTE_EQUAL(a, a - 0.049f, .05 ); + TTS_ABSOLUTE_EQUAL(a + 0.049f, a, .05 ); + TTS_ABSOLUTE_EQUAL(a - 0.049f, a, .05 ); + TTS_ABSOLUTE_EQUAL(a, a + 0.499f, .5 ); + TTS_ABSOLUTE_EQUAL(a, a - 0.499f, .5 ); + TTS_ABSOLUTE_EQUAL(a + 0.499f, a, .5 ); + TTS_ABSOLUTE_EQUAL(a - 0.499f, a, .5 ); + + #if !defined(__FAST_MATH__) T qnan = std::numeric_limits::quiet_NaN(); T inf = std::numeric_limits::infinity(); T minf = -inf; - TTS_ABSOLUTE_EQUAL(a , a , 0. ); TTS_ABSOLUTE_EQUAL(a , qnan , inf ); TTS_ABSOLUTE_EQUAL(qnan , a , inf ); TTS_ABSOLUTE_EQUAL(qnan , qnan , 0. ); @@ -35,15 +46,7 @@ TTS_CASE_TPL( "Absolute distance between floating point" TTS_ABSOLUTE_EQUAL(a , minf , inf ); TTS_ABSOLUTE_EQUAL(minf , a , inf ); TTS_ABSOLUTE_EQUAL(minf , minf , inf ); - - TTS_ABSOLUTE_EQUAL(a, a + 0.049f, .05 ); - TTS_ABSOLUTE_EQUAL(a, a - 0.049f, .05 ); - TTS_ABSOLUTE_EQUAL(a + 0.049f, a, .05 ); - TTS_ABSOLUTE_EQUAL(a - 0.049f, a, .05 ); - TTS_ABSOLUTE_EQUAL(a, a + 0.499f, .5 ); - TTS_ABSOLUTE_EQUAL(a, a - 0.499f, .5 ); - TTS_ABSOLUTE_EQUAL(a + 0.499f, a, .5 ); - TTS_ABSOLUTE_EQUAL(a - 0.499f, a, .5 ); + #endif }; TTS_CASE( "Absolute distance between boolean" ) diff --git a/test/precision/ieee.cpp b/test/precision/ieee.cpp index 94c775f..b90a47a 100644 --- a/test/precision/ieee.cpp +++ b/test/precision/ieee.cpp @@ -9,8 +9,10 @@ TTS_CASE("IEEE equality") { + #if !defined(__FAST_MATH__) float x = std::numeric_limits::quiet_NaN(); TTS_IEEE_EQUAL(x,x); + #endif TTS_IEEE_EQUAL(1.f, 1.f); TTS_IEEE_EQUAL(2. , 2. ); diff --git a/test/precision/relative.cpp b/test/precision/relative.cpp index 1742138..72f6e85 100644 --- a/test/precision/relative.cpp +++ b/test/precision/relative.cpp @@ -40,11 +40,22 @@ TTS_CASE_TPL( "Relative distance between floating point", float, double ) (::tts::type) { T a{1}; + + TTS_RELATIVE_EQUAL(a , a , 0. ); + TTS_RELATIVE_EQUAL(a, a + 0.049f, 5 ); + TTS_RELATIVE_EQUAL(a, a - 0.049f, 5 ); + TTS_RELATIVE_EQUAL(a + 0.049f, a, 5 ); + TTS_RELATIVE_EQUAL(a - 0.049f, a, 5 ); + TTS_RELATIVE_EQUAL(a, a + 0.499f, 50 ); + TTS_RELATIVE_EQUAL(a, a - 0.499f, 50 ); + TTS_RELATIVE_EQUAL(a + 0.499f, a, 50 ); + TTS_RELATIVE_EQUAL(a - 0.499f, a, 50 ); + + #if !defined(__FAST_MATH__) T qnan = std::numeric_limits::quiet_NaN(); T inf = std::numeric_limits::infinity(); T minf = -inf; - TTS_RELATIVE_EQUAL(a , a , 0. ); TTS_RELATIVE_EQUAL(a , qnan , inf ); TTS_RELATIVE_EQUAL(qnan , a , inf ); TTS_RELATIVE_EQUAL(qnan , qnan , 0. ); @@ -56,15 +67,7 @@ TTS_CASE_TPL( "Relative distance between floating point", float, double ) TTS_RELATIVE_EQUAL(a , minf , inf ); TTS_RELATIVE_EQUAL(minf , a , inf ); TTS_RELATIVE_EQUAL(minf , minf , inf ); - - TTS_RELATIVE_EQUAL(a, a + 0.049f, 5 ); - TTS_RELATIVE_EQUAL(a, a - 0.049f, 5 ); - TTS_RELATIVE_EQUAL(a + 0.049f, a, 5 ); - TTS_RELATIVE_EQUAL(a - 0.049f, a, 5 ); - TTS_RELATIVE_EQUAL(a, a + 0.499f, 50 ); - TTS_RELATIVE_EQUAL(a, a - 0.499f, 50 ); - TTS_RELATIVE_EQUAL(a + 0.499f, a, 50 ); - TTS_RELATIVE_EQUAL(a - 0.499f, a, 50 ); + #endif }; #include "my_real.hpp" diff --git a/test/precision/ulp.cpp b/test/precision/ulp.cpp index db1d14f..36ed3ec 100644 --- a/test/precision/ulp.cpp +++ b/test/precision/ulp.cpp @@ -20,12 +20,14 @@ TTS_CASE("ULP distance") TTS_CASE( "ULP distance between boolean" ) { - auto const inf = std::numeric_limits::infinity(); - TTS_ULP_EQUAL(true , true , 0. ); - TTS_ULP_EQUAL(true , false , inf ); TTS_ULP_EQUAL(false, false , 0. ); + + #if !defined(__FAST_MATH__) + auto const inf = std::numeric_limits::infinity(); + TTS_ULP_EQUAL(true , false , inf ); TTS_ULP_EQUAL(false, true , inf ); + #endif }; TTS_CASE_TPL( "ULP distance between integers"