huangcm
2025-02-28 b45e871a67cd1272e3da9ba5bd383f832b0f1824
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
 *  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)
 */
 
#include "catch_approx.h"
#include "catch_enforce.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 {
 
    Approx::Approx ( double value )
    :   m_epsilon( 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(m_value)));
    }
 
    void Approx::setMargin(double margin) {
        CATCH_ENFORCE(margin >= 0,
            "Invalid Approx::margin: " << margin << '.'
            << " Approx::Margin has to be non-negative.");
        m_margin = margin;
    }
 
    void Approx::setEpsilon(double epsilon) {
        CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
            "Invalid Approx::epsilon: " << epsilon << '.'
            << " Approx::epsilon has to be in [0, 1]");
        m_epsilon = epsilon;
    }
 
} // end namespace Detail
 
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
 
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
    return value.toString();
}
 
} // end namespace Catch