| // Copyright Catch2 Authors | |
| // Distributed under the Boost Software License, Version 1.0. | |
| // (See accompanying file LICENSE.txt or copy at | |
| // https://www.boost.org/LICENSE_1_0.txt) | |
| // SPDX-License-Identifier: BSL-1.0 | |
| #include <catch2/catch_approx.hpp> | |
| #include <catch2/internal/catch_enforce.hpp> | |
| #include <catch2/internal/catch_reusable_string_stream.hpp> | |
| #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 { | |
| Approx::Approx ( double value ) | |
| : m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ), | |
| m_margin( 0.0 ), | |
| m_scale( 0.0 ), | |
| m_value( value ) | |
| {} | |
| Approx Approx::custom() { | |
| return Approx( 0 ); | |
| } | |
| Approx Approx::operator-() const { | |
| auto temp(*this); | |
| temp.m_value = -temp.m_value; | |
| return temp; | |
| } | |
| std::string Approx::toString() const { | |
| ReusableStringStream rss; | |
| rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; | |
| return rss.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(std::isinf(m_value)? 0 : m_value))); | |
| } | |
| void Approx::setMargin(double newMargin) { | |
| CATCH_ENFORCE(newMargin >= 0, | |
| "Invalid Approx::margin: " << newMargin << '.' | |
| << " Approx::Margin has to be non-negative."); | |
| m_margin = newMargin; | |
| } | |
| void Approx::setEpsilon(double newEpsilon) { | |
| CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, | |
| "Invalid Approx::epsilon: " << newEpsilon << '.' | |
| << " Approx::epsilon has to be in [0, 1]"); | |
| m_epsilon = newEpsilon; | |
| } | |
| namespace literals { | |
| Approx operator ""_a(long double val) { | |
| return Approx(val); | |
| } | |
| Approx operator ""_a(unsigned long long val) { | |
| return Approx(val); | |
| } | |
| } // end namespace literals | |
| std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) { | |
| return value.toString(); | |
| } | |
| } // end namespace Catch |