mirror of
https://github.com/catchorg/Catch2.git
synced 2024-12-23 03:43:28 +01:00
Allow full range of target ULP values for the ULPMatcher
Previously it was limited to roughly 2 billion ULPs, rather than the roughly 2^64 possible ones.
This commit is contained in:
parent
ebc5609484
commit
c38a5caa2e
@ -34,34 +34,22 @@ enum class FloatingPointKind : uint8_t {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
struct Converter;
|
||||
|
||||
template <>
|
||||
struct Converter<float> {
|
||||
int32_t convert(float f) {
|
||||
static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
|
||||
Converter(float f) {
|
||||
std::memcpy(&i, &f, sizeof(f));
|
||||
}
|
||||
int32_t i;
|
||||
};
|
||||
std::memcpy(&i, &f, sizeof(f));
|
||||
return i;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct Converter<double> {
|
||||
int64_t convert(double d) {
|
||||
static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
|
||||
Converter(double d) {
|
||||
std::memcpy(&i, &d, sizeof(d));
|
||||
}
|
||||
int64_t i;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto convert(T t) -> Converter<T> {
|
||||
return Converter<T>(t);
|
||||
std::memcpy(&i, &d, sizeof(d));
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename FP>
|
||||
bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
|
||||
bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
|
||||
// Comparison with NaN should always be false.
|
||||
// This way we can rule it out before getting into the ugly details
|
||||
if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
|
||||
@ -71,13 +59,13 @@ bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
|
||||
auto lc = convert(lhs);
|
||||
auto rc = convert(rhs);
|
||||
|
||||
if ((lc.i < 0) != (rc.i < 0)) {
|
||||
if ((lc < 0) != (rc < 0)) {
|
||||
// Potentially we can have +0 and -0
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
auto ulpDiff = std::abs(lc.i - rc.i);
|
||||
return ulpDiff <= maxUlpDiff;
|
||||
auto ulpDiff = std::abs(lc - rc);
|
||||
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
|
||||
}
|
||||
|
||||
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
|
||||
@ -99,8 +87,8 @@ namespace Catch {
|
||||
#endif
|
||||
|
||||
template <typename FP>
|
||||
FP step(FP start, FP direction, int steps) {
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
FP step(FP start, FP direction, uint64_t steps) {
|
||||
for (uint64_t i = 0; i < steps; ++i) {
|
||||
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
|
||||
start = Catch::nextafter(start, direction);
|
||||
#else
|
||||
@ -133,10 +121,11 @@ namespace Floating {
|
||||
}
|
||||
|
||||
|
||||
WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
|
||||
WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)
|
||||
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
|
||||
CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
|
||||
<< " ULPs have to be non-negative.");
|
||||
CATCH_ENFORCE(m_type == FloatingPointKind::Double
|
||||
|| m_ulps < std::numeric_limits<uint32_t>::max(),
|
||||
"Provided ULP is impossibly large for a float comparison.");
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
@ -190,11 +179,11 @@ namespace Floating {
|
||||
|
||||
|
||||
|
||||
Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
|
||||
Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
|
||||
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
|
||||
}
|
||||
|
||||
Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
|
||||
Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
|
||||
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
|
||||
}
|
||||
|
||||
|
@ -26,12 +26,12 @@ namespace Matchers {
|
||||
};
|
||||
|
||||
struct WithinUlpsMatcher : MatcherBase<double> {
|
||||
WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
|
||||
WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);
|
||||
bool match(double const& matchee) const override;
|
||||
std::string describe() const override;
|
||||
private:
|
||||
double m_target;
|
||||
int m_ulps;
|
||||
uint64_t m_ulps;
|
||||
FloatingPointKind m_type;
|
||||
};
|
||||
|
||||
@ -40,8 +40,8 @@ namespace Matchers {
|
||||
|
||||
// The following functions create the actual matcher objects.
|
||||
// This allows the types to be inferred
|
||||
Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
|
||||
Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
|
||||
Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
|
||||
Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
|
||||
Floating::WithinAbsMatcher WithinAbs(double target, double margin);
|
||||
|
||||
} // namespace Matchers
|
||||
|
@ -408,7 +408,6 @@ Matchers.tests.cpp:<line number>: passed: 1., WithinAbs(2., 0.5) || WithinULP(1.
|
||||
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)
|
||||
Matchers.tests.cpp:<line number>: passed: WithinULP(1., -1), std::domain_error
|
||||
Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(1.f, 0) for: 1.0f is within 0.0 of 1.0
|
||||
Matchers.tests.cpp:<line number>: passed: 0.f, WithinAbs(1.f, 1) for: 0.0f is within 1.0 of 1.0
|
||||
Matchers.tests.cpp:<line number>: passed: 0.f, !WithinAbs(1.f, 0.99f) for: 0.0f not is within 0.9900000095 of 1.0
|
||||
@ -429,7 +428,7 @@ Matchers.tests.cpp:<line number>: passed: 1.f, WithinAbs(2.f, 0.5) || WithinULP(
|
||||
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)
|
||||
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, -1), std::domain_error
|
||||
Matchers.tests.cpp:<line number>: passed: WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
|
||||
|
@ -1381,5 +1381,5 @@ due to unexpected exception with message:
|
||||
|
||||
===============================================================================
|
||||
test cases: 300 | 226 passed | 70 failed | 4 failed as expected
|
||||
assertions: 1565 | 1413 passed | 131 failed | 21 failed as expected
|
||||
assertions: 1564 | 1412 passed | 131 failed | 21 failed as expected
|
||||
|
||||
|
@ -3020,9 +3020,6 @@ Matchers.tests.cpp:<line number>: PASSED:
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_NOTHROW( WithinULP(1., 0) )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS_AS( WithinULP(1., -1), std::domain_error )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Floating point matchers: float
|
||||
Margin
|
||||
@ -3149,7 +3146,7 @@ Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_NOTHROW( WithinULP(1.f, 0) )
|
||||
|
||||
Matchers.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS_AS( WithinULP(1.f, -1), std::domain_error )
|
||||
REQUIRE_THROWS_AS( WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Generators -- adapters
|
||||
@ -12503,5 +12500,5 @@ Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
===============================================================================
|
||||
test cases: 300 | 210 passed | 86 failed | 4 failed as expected
|
||||
assertions: 1582 | 1413 passed | 148 failed | 21 failed as expected
|
||||
assertions: 1581 | 1412 passed | 148 failed | 21 failed as expected
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuitesloose text artifact
|
||||
>
|
||||
<testsuite name="<exe-name>" errors="17" failures="132" tests="1583" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuite name="<exe-name>" errors="17" failures="132" tests="1582" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<properties>
|
||||
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
|
||||
<property name="random-seed" value="1"/>
|
||||
|
@ -3630,15 +3630,7 @@ Nor would this
|
||||
WithinULP(1., 0)
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
WithinULP(1., -1), std::domain_error
|
||||
</Original>
|
||||
<Expanded>
|
||||
WithinULP(1., -1), std::domain_error
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="4" failures="0" expectedFailures="0"/>
|
||||
<OverallResults successes="3" failures="0" expectedFailures="0"/>
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
@ -3815,10 +3807,10 @@ Nor would this
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
WithinULP(1.f, -1), std::domain_error
|
||||
WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error
|
||||
</Original>
|
||||
<Expanded>
|
||||
WithinULP(1.f, -1), std::domain_error
|
||||
WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="4" failures="0" expectedFailures="0"/>
|
||||
@ -14880,7 +14872,7 @@ loose text artifact
|
||||
</Section>
|
||||
<OverallResult success="true"/>
|
||||
</TestCase>
|
||||
<OverallResults successes="1413" failures="149" expectedFailures="21"/>
|
||||
<OverallResults successes="1412" failures="149" expectedFailures="21"/>
|
||||
</Group>
|
||||
<OverallResults successes="1413" failures="148" expectedFailures="21"/>
|
||||
<OverallResults successes="1412" failures="148" expectedFailures="21"/>
|
||||
</Catch>
|
||||
|
@ -372,7 +372,7 @@ namespace { namespace MatchersTests {
|
||||
REQUIRE_THROWS_AS(WithinAbs(1.f, -1.f), std::domain_error);
|
||||
|
||||
REQUIRE_NOTHROW(WithinULP(1.f, 0));
|
||||
REQUIRE_THROWS_AS(WithinULP(1.f, -1), std::domain_error);
|
||||
REQUIRE_THROWS_AS(WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,7 +408,6 @@ namespace { namespace MatchersTests {
|
||||
REQUIRE_THROWS_AS(WithinAbs(1., -1.), std::domain_error);
|
||||
|
||||
REQUIRE_NOTHROW(WithinULP(1., 0));
|
||||
REQUIRE_THROWS_AS(WithinULP(1., -1), std::domain_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user