2017-07-19 10:01:06 +02:00
|
|
|
/*
|
|
|
|
* Created by Martin on 19/07/2017.
|
|
|
|
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
|
|
|
*
|
|
|
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
*/
|
|
|
|
|
2017-09-07 12:24:33 +02:00
|
|
|
#include "catch_approx.h"
|
2017-07-19 10:01:06 +02:00
|
|
|
|
2017-11-01 07:30:11 +01:00
|
|
|
#include <cmath>
|
2017-07-19 10:01:06 +02:00
|
|
|
#include <limits>
|
2018-09-03 10:15:49 +02:00
|
|
|
#include <stdexcept>
|
2017-07-19 10:01:06 +02:00
|
|
|
|
2017-11-01 07:30:11 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-07-19 10:01:06 +02:00
|
|
|
namespace Catch {
|
|
|
|
namespace Detail {
|
|
|
|
|
|
|
|
Approx::Approx ( double value )
|
|
|
|
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
|
|
|
m_margin( 0.0 ),
|
2017-10-26 09:19:57 +02:00
|
|
|
m_scale( 0.0 ),
|
2017-07-19 10:01:06 +02:00
|
|
|
m_value( value )
|
|
|
|
{}
|
|
|
|
|
|
|
|
Approx Approx::custom() {
|
|
|
|
return Approx( 0 );
|
|
|
|
}
|
|
|
|
|
2018-05-21 15:42:40 +02:00
|
|
|
Approx Approx::operator-() const {
|
|
|
|
auto temp(*this);
|
|
|
|
temp.m_value = -temp.m_value;
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-19 10:01:06 +02:00
|
|
|
std::string Approx::toString() const {
|
2017-11-07 19:01:10 +01:00
|
|
|
ReusableStringStream rss;
|
|
|
|
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
|
|
|
return rss.str();
|
2017-07-19 10:01:06 +02:00
|
|
|
}
|
|
|
|
|
2017-11-01 07:30:11 +01:00
|
|
|
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)));
|
|
|
|
}
|
|
|
|
|
2018-09-03 10:15:49 +02:00
|
|
|
void Approx::setMargin(double margin) {
|
|
|
|
if (margin < 0) {
|
|
|
|
throw std::domain_error
|
|
|
|
("Invalid Approx::margin: " +
|
|
|
|
Catch::Detail::stringify(margin) +
|
|
|
|
", Approx::Margin has to be non-negative.");
|
|
|
|
|
|
|
|
}
|
|
|
|
m_margin = margin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Approx::setEpsilon(double epsilon) {
|
|
|
|
if (epsilon < 0 || epsilon > 1.0) {
|
|
|
|
throw std::domain_error
|
|
|
|
("Invalid Approx::epsilon: " +
|
|
|
|
Catch::Detail::stringify(epsilon) +
|
|
|
|
", Approx::epsilon has to be between 0 and 1");
|
|
|
|
}
|
|
|
|
m_epsilon = epsilon;
|
|
|
|
}
|
|
|
|
|
2017-07-19 10:01:06 +02:00
|
|
|
} // end namespace Detail
|
|
|
|
|
2018-05-21 15:42:40 +02:00
|
|
|
namespace literals {
|
|
|
|
Detail::Approx operator "" _a(long double val) {
|
|
|
|
return Detail::Approx(val);
|
|
|
|
}
|
|
|
|
Detail::Approx operator "" _a(unsigned long long val) {
|
|
|
|
return Detail::Approx(val);
|
|
|
|
}
|
|
|
|
} // end namespace literals
|
|
|
|
|
2017-07-19 10:01:06 +02:00
|
|
|
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
|
|
|
|
return value.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace Catch
|