mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-01 12:55:40 +02:00
Approx cleanup: More tests, INFINITY handling, etc
This commit is contained in:
@@ -8,18 +8,22 @@
|
||||
|
||||
#include "catch_approx.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace {
|
||||
|
||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||
// But without the subtraction to allow for INFINITY in comparison
|
||||
bool marginComparison(double lhs, double rhs, double margin) {
|
||||
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
double dmax(double lhs, double rhs) {
|
||||
if (lhs < rhs) {
|
||||
return rhs;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
Approx::Approx ( double value )
|
||||
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
||||
m_margin( 0.0 ),
|
||||
@@ -37,6 +41,12 @@ namespace Detail {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
bool Approx::equalityComparisonImpl(const double other) const {
|
||||
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
|
||||
// Thanks to Richard Harris for his help refining the scaled margin value
|
||||
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
|
||||
}
|
||||
|
||||
} // end namespace Detail
|
||||
|
||||
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
|
||||
|
@@ -11,16 +11,15 @@
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_tostring.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
double dmax(double lhs, double rhs);
|
||||
|
||||
class Approx {
|
||||
private:
|
||||
bool equalityComparisonImpl(double other) const;
|
||||
|
||||
public:
|
||||
explicit Approx ( double value );
|
||||
|
||||
@@ -42,15 +41,8 @@ namespace Detail {
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator == ( const T& lhs, Approx const& rhs ) {
|
||||
// Thanks to Richard Harris for his help refining this formula
|
||||
auto lhs_v = static_cast<double>(lhs);
|
||||
|
||||
bool relativeOK = std::fabs( lhs_v - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + std::fabs(rhs.m_value) );
|
||||
|
||||
if (relativeOK) {
|
||||
return true;
|
||||
}
|
||||
return std::fabs(lhs_v - rhs.m_value) <= rhs.m_margin;
|
||||
return rhs.equalityComparisonImpl(lhs_v);
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
@@ -90,18 +82,21 @@ namespace Detail {
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& epsilon( T const& newEpsilon ) {
|
||||
double asDouble = static_cast<double>(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;
|
||||
double epsilonAsDouble = static_cast<double>(newEpsilon);
|
||||
CATCH_ENFORCE(epsilonAsDouble >= 0 && epsilonAsDouble <= 1.0,
|
||||
"Invalid Approx::epsilon: " << epsilonAsDouble
|
||||
<< ", Approx::epsilon has to be between 0 and 1");
|
||||
m_epsilon = epsilonAsDouble;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& margin( T const& newMargin ) {
|
||||
m_margin = static_cast<double>(newMargin);
|
||||
CATCH_ENFORCE(m_margin >= 0, "Invalid Approx::margin: " << m_margin << ", Approx::Margin has to be non-negative.");
|
||||
double marginAsDouble = static_cast<double>(newMargin);
|
||||
CATCH_ENFORCE(marginAsDouble >= 0,
|
||||
"Invalid Approx::margin: " << marginAsDouble
|
||||
<< ", Approx::Margin has to be non-negative.");
|
||||
m_margin = marginAsDouble;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user