Skip to content

Commit

Permalink
Show bound when stringifying the WithinULP matcher
Browse files Browse the repository at this point in the history
Closes #1581
  • Loading branch information
horenmar committed Jun 14, 2019
1 parent f0b7b0c commit d81ab73
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 61 deletions.
35 changes: 34 additions & 1 deletion include/internal/catch_matchers_floating.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <limits>

namespace Catch {
namespace Matchers {
Expand Down Expand Up @@ -74,8 +77,16 @@ bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
return ulpDiff <= maxUlpDiff;
}

template <typename FP>
FP step(FP start, FP direction, int steps) {
for (int i = 0; i < steps; ++i) {
start = std::nextafter(start, direction);
}
return start;
}

} // end anonymous namespace


namespace Catch {
namespace Matchers {
Expand Down Expand Up @@ -125,7 +136,29 @@ namespace Floating {
#endif

std::string WithinUlpsMatcher::describe() const {
return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
std::stringstream ret;

ret << "is within " << m_ulps << " ULPs of " << ::Catch::Detail::stringify(m_target);

if (m_type == FloatingPointKind::Float) {
ret << 'f';
}

ret << " ([";
ret << std::fixed << std::setprecision(std::numeric_limits<double>::max_digits10);
if (m_type == FloatingPointKind::Double) {
ret << step(m_target, static_cast<double>(-INFINITY), m_ulps)
<< ", "
<< step(m_target, static_cast<double>(INFINITY), m_ulps);
} else {
ret << step<float>(static_cast<float>(m_target), -INFINITY, m_ulps)
<< ", "
<< step<float>(static_cast<float>(m_target), INFINITY, m_ulps);
}
ret << "])";

return ret.str();
//return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
}

}// namespace Floating
Expand Down
40 changes: 20 additions & 20 deletions projects/SelfTest/Baselines/compact.sw.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -401,16 +401,16 @@ Matchers.tests.cpp:<line number>: passed: 11., !WithinAbs(10., 0.5) for: 11.0 no
Matchers.tests.cpp:<line number>: passed: 10., !WithinAbs(11., 0.5) for: 10.0 not is within 0.5 of 11.0
Matchers.tests.cpp:<line number>: passed: -10., WithinAbs(-10., 0.5) for: -10.0 is within 0.5 of -10.0
Matchers.tests.cpp:<line number>: passed: -10., WithinAbs(-9.6, 0.5) for: -10.0 is within 0.5 of -9.6
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0
Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0
Matchers.tests.cpp:<line number>: passed: nextafter(1., 0.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0
Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), !WithinULP(1., 0) for: 1.0 not is within 0 ULPs of 1.0
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0
Matchers.tests.cpp:<line number>: passed: -0., WithinULP(0., 0) for: -0.0 is within 0 ULPs of 0.0
Matchers.tests.cpp:<line number>: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(1., 0.5) || WithinULP(2., 1) for: 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0 )
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(2., 0.5) || WithinULP(1., 0) for: 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0 )
Matchers.tests.cpp:<line number>: passed: NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) for: nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf )
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])
Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 ([0.99999999999999989, 1.00000000000000022])
Matchers.tests.cpp:<line number>: passed: nextafter(1., 0.), WithinULP(1., 1) for: 1.0 is within 1 ULPs of 1.0 ([0.99999999999999989, 1.00000000000000022])
Matchers.tests.cpp:<line number>: passed: nextafter(1., 2.), !WithinULP(1., 0) for: 1.0 not is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])
Matchers.tests.cpp:<line number>: passed: 1., WithinULP(1., 0) for: 1.0 is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])
Matchers.tests.cpp:<line number>: passed: -0., WithinULP(0., 0) for: -0.0 is within 0 ULPs of 0.0 ([0.00000000000000000, 0.00000000000000000])
Matchers.tests.cpp:<line number>: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf ([nan, nan])
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(1., 0.5) || WithinULP(2., 1) for: 1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0 ([1.99999999999999978, 2.00000000000000044]) )
Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(2., 0.5) || WithinULP(1., 0) for: 1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000]) )
Matchers.tests.cpp:<line number>: passed: NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) for: nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf ([nan, nan]) )
Matchers.tests.cpp:<line number>: passed: WithinAbs(1., 0.)
Matchers.tests.cpp:<line number>: passed: WithinAbs(1., -1.), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinULP(1., 0)
Expand All @@ -425,16 +425,16 @@ Matchers.tests.cpp:<line number>: passed: 11.f, !WithinAbs(10.f, 0.5f) for: 11.0
Matchers.tests.cpp:<line number>: passed: 10.f, !WithinAbs(11.f, 0.5f) for: 10.0f not is within 0.5 of 11.0
Matchers.tests.cpp:<line number>: passed: -10.f, WithinAbs(-10.f, 0.5f) for: -10.0f is within 0.5 of -10.0
Matchers.tests.cpp:<line number>: passed: -10.f, WithinAbs(-9.6f, 0.5f) for: -10.0f is within 0.5 of -9.6000003815
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 0.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), !WithinULP(1.f, 0) for: 1.0f not is within 0 ULPs of 1.0f
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f
Matchers.tests.cpp:<line number>: passed: -0.f, WithinULP(0.f, 0) for: -0.0f is within 0 ULPs of 0.0f
Matchers.tests.cpp:<line number>: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1) for: 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.0f )
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0) for: 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0f )
Matchers.tests.cpp:<line number>: passed: NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) for: nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf )
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000])
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f ([0.99999994039535522, 1.00000011920928955])
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 0.f), WithinULP(1.f, 1) for: 1.0f is within 1 ULPs of 1.0f ([0.99999994039535522, 1.00000011920928955])
Matchers.tests.cpp:<line number>: passed: nextafter(1.f, 2.f), !WithinULP(1.f, 0) for: 1.0f not is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000])
Matchers.tests.cpp:<line number>: passed: 1.f, WithinULP(1.f, 0) for: 1.0f is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000])
Matchers.tests.cpp:<line number>: passed: -0.f, WithinULP(0.f, 0) for: -0.0f is within 0 ULPs of 0.0f ([0.00000000000000000, 0.00000000000000000])
Matchers.tests.cpp:<line number>: passed: NAN, !WithinULP(NAN, 123) for: nanf not is within 123 ULPs of nanf ([nan, nan])
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1) for: 1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.0f ([0.99999994039535522, 1.00000011920928955]) )
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0) for: 1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000]) )
Matchers.tests.cpp:<line number>: passed: NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) for: nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf ([nan, nan]) )
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, 0.f)
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, -1.f), std::domain_error
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, 0)
Expand Down
47 changes: 27 additions & 20 deletions projects/SelfTest/Baselines/console.sw.approved.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2984,37 +2984,37 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., WithinULP(1., 0) )
with expansion:
1.0 is within 0 ULPs of 1.0
1.0 is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( nextafter(1., 2.), WithinULP(1., 1) )
with expansion:
1.0 is within 1 ULPs of 1.0
1.0 is within 1 ULPs of 1.0 ([0.99999999999999989, 1.00000000000000022])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( nextafter(1., 0.), WithinULP(1., 1) )
with expansion:
1.0 is within 1 ULPs of 1.0
1.0 is within 1 ULPs of 1.0 ([0.99999999999999989, 1.00000000000000022])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( nextafter(1., 2.), !WithinULP(1., 0) )
with expansion:
1.0 not is within 0 ULPs of 1.0
1.0 not is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., WithinULP(1., 0) )
with expansion:
1.0 is within 0 ULPs of 1.0
1.0 is within 0 ULPs of 1.0 ([1.00000000000000000, 1.00000000000000000])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( -0., WithinULP(0., 0) )
with expansion:
-0.0 is within 0 ULPs of 0.0
-0.0 is within 0 ULPs of 0.0 ([0.00000000000000000, 0.00000000000000000])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( NAN, !WithinULP(NAN, 123) )
with expansion:
nanf not is within 123 ULPs of nanf
nanf not is within 123 ULPs of nanf ([nan, nan])

-------------------------------------------------------------------------------
Floating point matchers: double
Expand All @@ -3026,17 +3026,20 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., WithinAbs(1., 0.5) || WithinULP(2., 1) )
with expansion:
1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0 )
1.0 ( is within 0.5 of 1.0 or is within 1 ULPs of 2.0 ([1.99999999999999978,
2.00000000000000044]) )

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1., WithinAbs(2., 0.5) || WithinULP(1., 0) )
with expansion:
1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0 )
1.0 ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0 ([1.00000000000000000,
1.00000000000000000]) )

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) )
with expansion:
nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf )
nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf ([nan, nan])
)

-------------------------------------------------------------------------------
Floating point matchers: double
Expand Down Expand Up @@ -3124,37 +3127,38 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1.f, WithinULP(1.f, 0) )
with expansion:
1.0f is within 0 ULPs of 1.0f
1.0f is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( nextafter(1.f, 2.f), WithinULP(1.f, 1) )
with expansion:
1.0f is within 1 ULPs of 1.0f
1.0f is within 1 ULPs of 1.0f ([0.99999994039535522, 1.00000011920928955])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( nextafter(1.f, 0.f), WithinULP(1.f, 1) )
with expansion:
1.0f is within 1 ULPs of 1.0f
1.0f is within 1 ULPs of 1.0f ([0.99999994039535522, 1.00000011920928955])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( nextafter(1.f, 2.f), !WithinULP(1.f, 0) )
with expansion:
1.0f not is within 0 ULPs of 1.0f
1.0f not is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000]
)

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1.f, WithinULP(1.f, 0) )
with expansion:
1.0f is within 0 ULPs of 1.0f
1.0f is within 0 ULPs of 1.0f ([1.00000000000000000, 1.00000000000000000])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( -0.f, WithinULP(0.f, 0) )
with expansion:
-0.0f is within 0 ULPs of 0.0f
-0.0f is within 0 ULPs of 0.0f ([0.00000000000000000, 0.00000000000000000])

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( NAN, !WithinULP(NAN, 123) )
with expansion:
nanf not is within 123 ULPs of nanf
nanf not is within 123 ULPs of nanf ([nan, nan])

-------------------------------------------------------------------------------
Floating point matchers: float
Expand All @@ -3166,17 +3170,20 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1.f, WithinAbs(1.f, 0.5) || WithinULP(1.f, 1) )
with expansion:
1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.0f )
1.0f ( is within 0.5 of 1.0 or is within 1 ULPs of 1.0f ([0.
99999994039535522, 1.00000011920928955]) )

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( 1.f, WithinAbs(2.f, 0.5) || WithinULP(1.f, 0) )
with expansion:
1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0f )
1.0f ( is within 0.5 of 2.0 or is within 0 ULPs of 1.0f ([1.
00000000000000000, 1.00000000000000000]) )

Matchers.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( NAN, !(WithinAbs(NAN, 100) || WithinULP(NAN, 123)) )
with expansion:
nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf )
nanf not ( is within 100.0 of nan or is within 123 ULPs of nanf ([nan, nan])
)

-------------------------------------------------------------------------------
Floating point matchers: float
Expand Down
Loading

0 comments on commit d81ab73

Please sign in to comment.