Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
catch_matchers_floating.cpp
Go to the documentation of this file.
1/*
2 * Created by Martin on 07/11/2017.
3 *
4 * Distributed under the Boost Software License, Version 1.0. (See accompanying
5 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 */
7
9#include "catch_enforce.h"
10#include "catch_polyfills.hpp"
11#include "catch_to_string.hpp"
12#include "catch_tostring.h"
13
14#include <cstdlib>
15#include <cstdint>
16#include <cstring>
17
18namespace Catch {
19namespace Matchers {
20namespace Floating {
22 Float,
23 Double
24};
25}
26}
27}
28
29namespace {
30
31template <typename T>
32struct Converter;
33
34template <>
35struct Converter<float> {
36 static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
37 Converter(float f) {
38 std::memcpy(&i, &f, sizeof(f));
39 }
40 int32_t i;
41};
42
43template <>
44struct Converter<double> {
45 static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
46 Converter(double d) {
47 std::memcpy(&i, &d, sizeof(d));
48 }
49 int64_t i;
50};
51
52template <typename T>
53auto convert(T t) -> Converter<T> {
54 return Converter<T>(t);
55}
56
57template <typename FP>
58bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
59 // Comparison with NaN should always be false.
60 // This way we can rule it out before getting into the ugly details
61 if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
62 return false;
63 }
64
65 auto lc = convert(lhs);
66 auto rc = convert(rhs);
67
68 if ((lc.i < 0) != (rc.i < 0)) {
69 // Potentially we can have +0 and -0
70 return lhs == rhs;
71 }
72
73 auto ulpDiff = std::abs(lc.i - rc.i);
74 return ulpDiff <= maxUlpDiff;
75}
76
77}
78
79
80namespace Catch {
81namespace Matchers {
82namespace Floating {
83 WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
84 :m_target{ target }, m_margin{ margin } {
85 CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
86 << " Margin has to be non-negative.");
87 }
88
89 // Performs equivalent check of std::fabs(lhs - rhs) <= margin
90 // But without the subtraction to allow for INFINITY in comparison
91 bool WithinAbsMatcher::match(double const& matchee) const {
92 return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
93 }
94
95 std::string WithinAbsMatcher::describe() const {
96 return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
97 }
98
99
101 :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
102 CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
103 << " ULPs have to be non-negative.");
104 }
105
106#if defined(__clang__)
107#pragma clang diagnostic push
108// Clang <3.5 reports on the default branch in the switch below
109#pragma clang diagnostic ignored "-Wunreachable-code"
110#endif
111
112 bool WithinUlpsMatcher::match(double const& matchee) const {
113 switch (m_type) {
115 return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
117 return almostEqualUlps<double>(matchee, m_target, m_ulps);
118 default:
119 CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );
120 }
121 }
122
123#if defined(__clang__)
124#pragma clang diagnostic pop
125#endif
126
127 std::string WithinUlpsMatcher::describe() const {
128 return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
129 }
130
131}// namespace Floating
132
133
134
135Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
137}
138
139Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
141}
142
143Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
144 return Floating::WithinAbsMatcher(target, margin);
145}
146
147} // namespace Matchers
148} // namespace Catch
149
#define CATCH_INTERNAL_ERROR(msg)
#define CATCH_ENFORCE(condition, msg)
std::string stringify(const T &e)
Floating::WithinAbsMatcher WithinAbs(double target, double margin)
Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff)
std::string to_string(T const &t)
bool isnan(float f)
#define T(meth, val, expected)
signed __int64 int64_t
Definition stdint.h:135
signed int int32_t
Definition stdint.h:123
unsigned char uint8_t
Definition stdint.h:124
bool match(double const &matchee) const override
WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
bool match(double const &matchee) const override
yh_rc rc