From 00af677577973758b3b35e1c94ab4142c45c3f67 Mon Sep 17 00:00:00 2001 From: Pfiffikus <2845742+Pfiffikus@users.noreply.github.com> Date: Thu, 26 Oct 2017 09:19:57 +0200 Subject: [PATCH] Approx rework: default scale == 0, epsilon applies to Approx::value Also adds check to Approx::epsilon that the new epsilon has a valid (ie one between 0 and 1) Based on http://realtimecollisiondetection.net/blog/?p=89 https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html https://en.wikipedia.org/wiki/Approximation_error#Formal_Definition The given epsilon should refer to the target value, otherwise the result would be unexpected, e.g. 101.02 == Approx(100).epsilon(0.01) is true. The default scale should be invisible, thus, e.g. 101.01 == Approx(100).epsilon(0.01) gets false. Finally even 101.000001 == Approx(100).epsilon(0.01) is false --- include/internal/catch_approx.cpp | 2 +- include/internal/catch_approx.h | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/internal/catch_approx.cpp b/include/internal/catch_approx.cpp index ca3ac94a..826a1049 100644 --- a/include/internal/catch_approx.cpp +++ b/include/internal/catch_approx.cpp @@ -23,7 +23,7 @@ namespace Detail { Approx::Approx ( double value ) : m_epsilon( std::numeric_limits::epsilon()*100 ), m_margin( 0.0 ), - m_scale( 1.0 ), + m_scale( 0.0 ), m_value( value ) {} diff --git a/include/internal/catch_approx.h b/include/internal/catch_approx.h index 69428c8a..8ca7f315 100644 --- a/include/internal/catch_approx.h +++ b/include/internal/catch_approx.h @@ -44,8 +44,9 @@ namespace Detail { friend bool operator == ( const T& lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula auto lhs_v = static_cast(lhs); - bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + - dmax(std::fabs(lhs_v), std::fabs(rhs.m_value))); + + bool relativeOK = std::fabs( lhs_v - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + std::fabs(rhs.m_value) ); + if (relativeOK) { return true; } @@ -89,7 +90,11 @@ namespace Detail { template ::value>::type> Approx& epsilon( T const& newEpsilon ) { - m_epsilon = static_cast(newEpsilon); + double asDouble = static_cast(newEpsilon); + CATCH_ENFORCE(asDouble >= 0 && asDouble <= 1.0, + "Invalid Approx::epsilon: " << m_epsilon << + ", Approx::epsilon has to be between 0 and 1"); + m_epsilon = asDouble; return *this; }