Skip to content

Commit

Permalink
Fix bad interaction with /fp:fast
Browse files Browse the repository at this point in the history
  • Loading branch information
jfalcou committed Dec 8, 2023
1 parent 71507e5 commit e210aa8
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 65 deletions.
25 changes: 18 additions & 7 deletions include/tts/engine/precision.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,19 @@
#include <limits>
#include <cmath>


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
Expand All @@ -35,9 +46,9 @@ namespace tts
}
else if constexpr(std::is_floating_point_v<T>) // 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<double>::infinity();

return std::abs(a - b);
Expand Down Expand Up @@ -81,9 +92,9 @@ namespace tts
{ return a == b ? 0. : 100.; }
else if constexpr(std::is_floating_point_v<T>) // 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<double>::infinity();

return 100. * (std::abs(a - b) / std::max(T(1), std::max(std::abs(a), std::abs(b))));
Expand Down Expand Up @@ -131,7 +142,7 @@ namespace tts
{
using ui_t = std::conditional_t<std::is_same_v<T, float>, 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.;
}
Expand Down Expand Up @@ -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<typename T, typename U> inline bool is_ieee_equal(T const &a, U const &b)
{
if constexpr(std::is_floating_point_v<T>) // IEEE cases
{
return (a==b) || (std::isnan(a) && std::isnan(b));
return (a==b) || (detail::isnan(a) && detail::isnan(b));
}
else
{
Expand Down
10 changes: 5 additions & 5 deletions include/tts/test/ranges.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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::size_t>(std::ceil(ulp*2));
else if(std::isinf(ulp)) bucket = nb_buckets-1;
else bucket = std::min( nb_buckets-2
, static_cast<std::size_t>(std::log2(next2(ulp))+4)
);
if (ulp <= 1.5 ) bucket = static_cast<std::size_t>(std::ceil(ulp*2));
else if(detail::isinf(ulp)) bucket = nb_buckets-1;
else bucket = std::min ( nb_buckets-2
, static_cast<std::size_t>(std::log2(next2(ulp))+4)
);
return bucket;
}

Expand Down
32 changes: 21 additions & 11 deletions standalone/tts/tts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,16 @@ namespace tts::detail
#include <cmath>
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<typename T, typename U> inline double absolute_distance(T const &a, U const &b)
{
if constexpr(std::is_same_v<T, U>)
Expand All @@ -1350,8 +1360,8 @@ namespace tts
}
else if constexpr(std::is_floating_point_v<T>)
{
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<double>::infinity();
return std::abs(a - b);
}
Expand Down Expand Up @@ -1382,8 +1392,8 @@ namespace tts
{ return a == b ? 0. : 100.; }
else if constexpr(std::is_floating_point_v<T>)
{
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<double>::infinity();
return 100. * (std::abs(a - b) / std::max(T(1), std::max(std::abs(a), std::abs(b))));
}
Expand Down Expand Up @@ -1417,7 +1427,7 @@ namespace tts
else if constexpr(std::is_floating_point_v<T>)
{
using ui_t = std::conditional_t<std::is_same_v<T, float>, 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.;
}
Expand Down Expand Up @@ -1458,7 +1468,7 @@ namespace tts
{
if constexpr(std::is_floating_point_v<T>)
{
return (a==b) || (std::isnan(a) && std::isnan(b));
return (a==b) || (detail::isnan(a) && detail::isnan(b));
}
else
{
Expand Down Expand Up @@ -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::size_t>(std::ceil(ulp*2));
else if(std::isinf(ulp)) bucket = nb_buckets-1;
else bucket = std::min( nb_buckets-2
, static_cast<std::size_t>(std::log2(next2(ulp))+4)
);
if (ulp <= 1.5 ) bucket = static_cast<std::size_t>(std::ceil(ulp*2));
else if(detail::isinf(ulp)) bucket = nb_buckets-1;
else bucket = std::min ( nb_buckets-2
, static_cast<std::size_t>(std::log2(next2(ulp))+4)
);
return bucket;
}
template<typename Type,typename In, typename Out, typename Func>
Expand Down
38 changes: 19 additions & 19 deletions test/generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ template<typename T> struct array_of
template<typename L> struct make;
template<typename... Ls> struct make<tts::types<Ls...>>
{
using type = tts::types<std::array<Ls,10>...>;
using type = tts::types<std::array<Ls,9>...>;
};

using types_list = typename make<T>::type;
Expand Down Expand Up @@ -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.} }
)
Expand All @@ -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<v_t>(0);
auto w2 = static_cast<v_t>(100);
auto step = (w2-w1)/9;

auto w2 = static_cast<v_t>(128);
auto step = (w2-w1)/8;
T btw_ref;
for(std::size_t i=0;i<btw.size();++i)
{
btw_ref[i] = std::min( static_cast<v_t>(w1 + i*step), w2);
}

TTS_EXPR_IS(value , (std::array<v_t, 10> const&) );
TTS_EXPR_IS(rmp , (std::array<v_t, 10> const&) );
TTS_EXPR_IS(rmps , (std::array<v_t, 10> const&) );
TTS_EXPR_IS(rrmp , (std::array<v_t, 10> const&) );
TTS_EXPR_IS(rrmps , (std::array<v_t, 10> const&) );
TTS_EXPR_IS(btw , (std::array<v_t, 10> const&) );
TTS_EXPR_IS(rng , (std::array<v_t, 10> const&) );
TTS_EXPR_IS(urng , (std::array<double, 10> const&) );
TTS_EXPR_IS(value , (std::array<v_t, 9> const&) );
TTS_EXPR_IS(rmp , (std::array<v_t, 9> const&) );
TTS_EXPR_IS(rmps , (std::array<v_t, 9> const&) );
TTS_EXPR_IS(rrmp , (std::array<v_t, 9> const&) );
TTS_EXPR_IS(rrmps , (std::array<v_t, 9> const&) );
TTS_EXPR_IS(btw , (std::array<v_t, 9> const&) );
TTS_EXPR_IS(rng , (std::array<v_t, 9> const&) );
TTS_EXPR_IS(urng , (std::array<double, 9> const&) );

TTS_ALL_EQUAL(value , value_ref );
TTS_ALL_EQUAL(rmp , rmp_ref );
Expand All @@ -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)
{
Expand Down
23 changes: 13 additions & 10 deletions test/precision/absolute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,22 @@ TTS_CASE_TPL( "Absolute distance between floating point"
<typename T>(::tts::type<T>)
{
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<T>::quiet_NaN();
T inf = std::numeric_limits<T>::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. );
Expand All @@ -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" )
Expand Down
2 changes: 2 additions & 0 deletions test/precision/ieee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@

TTS_CASE("IEEE equality")
{
#if !defined(__FAST_MATH__)
float x = std::numeric_limits<float>::quiet_NaN();
TTS_IEEE_EQUAL(x,x);
#endif

TTS_IEEE_EQUAL(1.f, 1.f);
TTS_IEEE_EQUAL(2. , 2. );
Expand Down
23 changes: 13 additions & 10 deletions test/precision/relative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,22 @@ TTS_CASE_TPL( "Relative distance between floating point", float, double )
<typename T>(::tts::type<T>)
{
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<T>::quiet_NaN();
T inf = std::numeric_limits<T>::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. );
Expand All @@ -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"
Expand Down
8 changes: 5 additions & 3 deletions test/precision/ulp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ TTS_CASE("ULP distance")

TTS_CASE( "ULP distance between boolean" )
{
auto const inf = std::numeric_limits<double>::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<double>::infinity();
TTS_ULP_EQUAL(true , false , inf );
TTS_ULP_EQUAL(false, true , inf );
#endif
};

TTS_CASE_TPL( "ULP distance between integers"
Expand Down

0 comments on commit e210aa8

Please sign in to comment.