mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 21:36:11 +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 {
|
namespace {
|
||||||
|
|
||||||
template <typename T>
|
int32_t convert(float f) {
|
||||||
struct Converter;
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct Converter<float> {
|
|
||||||
static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
|
static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
|
||||||
Converter(float f) {
|
|
||||||
std::memcpy(&i, &f, sizeof(f));
|
|
||||||
}
|
|
||||||
int32_t i;
|
int32_t i;
|
||||||
};
|
std::memcpy(&i, &f, sizeof(f));
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
int64_t convert(double d) {
|
||||||
struct Converter<double> {
|
|
||||||
static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
|
static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
|
||||||
Converter(double d) {
|
|
||||||
std::memcpy(&i, &d, sizeof(d));
|
|
||||||
}
|
|
||||||
int64_t i;
|
int64_t i;
|
||||||
};
|
std::memcpy(&i, &d, sizeof(d));
|
||||||
|
return i;
|
||||||
template <typename T>
|
|
||||||
auto convert(T t) -> Converter<T> {
|
|
||||||
return Converter<T>(t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FP>
|
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.
|
// Comparison with NaN should always be false.
|
||||||
// This way we can rule it out before getting into the ugly details
|
// This way we can rule it out before getting into the ugly details
|
||||||
if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
|
if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
|
||||||
@ -71,13 +59,13 @@ bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
|
|||||||
auto lc = convert(lhs);
|
auto lc = convert(lhs);
|
||||||
auto rc = convert(rhs);
|
auto rc = convert(rhs);
|
||||||
|
|
||||||
if ((lc.i < 0) != (rc.i < 0)) {
|
if ((lc < 0) != (rc < 0)) {
|
||||||
// Potentially we can have +0 and -0
|
// Potentially we can have +0 and -0
|
||||||
return lhs == rhs;
|
return lhs == rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ulpDiff = std::abs(lc.i - rc.i);
|
auto ulpDiff = std::abs(lc - rc);
|
||||||
return ulpDiff <= maxUlpDiff;
|
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
|
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
|
||||||
@ -99,8 +87,8 @@ namespace Catch {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename FP>
|
template <typename FP>
|
||||||
FP step(FP start, FP direction, int steps) {
|
FP step(FP start, FP direction, uint64_t steps) {
|
||||||
for (int i = 0; i < steps; ++i) {
|
for (uint64_t i = 0; i < steps; ++i) {
|
||||||
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
|
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
|
||||||
start = Catch::nextafter(start, direction);
|
start = Catch::nextafter(start, direction);
|
||||||
#else
|
#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 } {
|
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
|
||||||
CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
|
CATCH_ENFORCE(m_type == FloatingPointKind::Double
|
||||||
<< " ULPs have to be non-negative.");
|
|| m_ulps < std::numeric_limits<uint32_t>::max(),
|
||||||
|
"Provided ULP is impossibly large for a float comparison.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__clang__)
|
#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);
|
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);
|
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,12 +26,12 @@ namespace Matchers {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct WithinUlpsMatcher : MatcherBase<double> {
|
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;
|
bool match(double const& matchee) const override;
|
||||||
std::string describe() const override;
|
std::string describe() const override;
|
||||||
private:
|
private:
|
||||||
double m_target;
|
double m_target;
|
||||||
int m_ulps;
|
uint64_t m_ulps;
|
||||||
FloatingPointKind m_type;
|
FloatingPointKind m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,8 +40,8 @@ namespace Matchers {
|
|||||||
|
|
||||||
// The following functions create the actual matcher objects.
|
// The following functions create the actual matcher objects.
|
||||||
// This allows the types to be inferred
|
// This allows the types to be inferred
|
||||||
Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
|
Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
|
||||||
Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
|
Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
|
||||||
Floating::WithinAbsMatcher WithinAbs(double target, double margin);
|
Floating::WithinAbsMatcher WithinAbs(double target, double margin);
|
||||||
|
|
||||||
} // namespace Matchers
|
} // 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., 0.)
|
||||||
Matchers.tests.cpp:<line number>: passed: WithinAbs(1., -1.), std::domain_error
|
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., 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: 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, 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
|
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, 0.f)
|
||||||
Matchers.tests.cpp:<line number>: passed: WithinAbs(1.f, -1.f), std::domain_error
|
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, 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
|
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
|
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:
|
Matchers.tests.cpp:<line number>: PASSED:
|
||||||
REQUIRE_NOTHROW( WithinULP(1., 0) )
|
REQUIRE_NOTHROW( WithinULP(1., 0) )
|
||||||
|
|
||||||
Matchers.tests.cpp:<line number>: PASSED:
|
|
||||||
REQUIRE_THROWS_AS( WithinULP(1., -1), std::domain_error )
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Floating point matchers: float
|
Floating point matchers: float
|
||||||
Margin
|
Margin
|
||||||
@ -3149,7 +3146,7 @@ Matchers.tests.cpp:<line number>: PASSED:
|
|||||||
REQUIRE_NOTHROW( WithinULP(1.f, 0) )
|
REQUIRE_NOTHROW( WithinULP(1.f, 0) )
|
||||||
|
|
||||||
Matchers.tests.cpp:<line number>: PASSED:
|
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
|
Generators -- adapters
|
||||||
@ -12503,5 +12500,5 @@ Misc.tests.cpp:<line number>: PASSED:
|
|||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
test cases: 300 | 210 passed | 86 failed | 4 failed as expected
|
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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<testsuitesloose text artifact
|
<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>
|
<properties>
|
||||||
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
|
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
|
||||||
<property name="random-seed" value="1"/>
|
<property name="random-seed" value="1"/>
|
||||||
|
@ -3630,15 +3630,7 @@ Nor would this
|
|||||||
WithinULP(1., 0)
|
WithinULP(1., 0)
|
||||||
</Expanded>
|
</Expanded>
|
||||||
</Expression>
|
</Expression>
|
||||||
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
<OverallResults successes="3" failures="0" expectedFailures="0"/>
|
||||||
<Original>
|
|
||||||
WithinULP(1., -1), std::domain_error
|
|
||||||
</Original>
|
|
||||||
<Expanded>
|
|
||||||
WithinULP(1., -1), std::domain_error
|
|
||||||
</Expanded>
|
|
||||||
</Expression>
|
|
||||||
<OverallResults successes="4" failures="0" expectedFailures="0"/>
|
|
||||||
</Section>
|
</Section>
|
||||||
<OverallResult success="true"/>
|
<OverallResult success="true"/>
|
||||||
</TestCase>
|
</TestCase>
|
||||||
@ -3815,10 +3807,10 @@ Nor would this
|
|||||||
</Expression>
|
</Expression>
|
||||||
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
<Expression success="true" type="REQUIRE_THROWS_AS" filename="projects/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||||
<Original>
|
<Original>
|
||||||
WithinULP(1.f, -1), std::domain_error
|
WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error
|
||||||
</Original>
|
</Original>
|
||||||
<Expanded>
|
<Expanded>
|
||||||
WithinULP(1.f, -1), std::domain_error
|
WithinULP(1.f, static_cast<uint64_t>(-1)), std::domain_error
|
||||||
</Expanded>
|
</Expanded>
|
||||||
</Expression>
|
</Expression>
|
||||||
<OverallResults successes="4" failures="0" expectedFailures="0"/>
|
<OverallResults successes="4" failures="0" expectedFailures="0"/>
|
||||||
@ -14880,7 +14872,7 @@ loose text artifact
|
|||||||
</Section>
|
</Section>
|
||||||
<OverallResult success="true"/>
|
<OverallResult success="true"/>
|
||||||
</TestCase>
|
</TestCase>
|
||||||
<OverallResults successes="1413" failures="149" expectedFailures="21"/>
|
<OverallResults successes="1412" failures="149" expectedFailures="21"/>
|
||||||
</Group>
|
</Group>
|
||||||
<OverallResults successes="1413" failures="148" expectedFailures="21"/>
|
<OverallResults successes="1412" failures="148" expectedFailures="21"/>
|
||||||
</Catch>
|
</Catch>
|
||||||
|
@ -372,7 +372,7 @@ namespace { namespace MatchersTests {
|
|||||||
REQUIRE_THROWS_AS(WithinAbs(1.f, -1.f), std::domain_error);
|
REQUIRE_THROWS_AS(WithinAbs(1.f, -1.f), std::domain_error);
|
||||||
|
|
||||||
REQUIRE_NOTHROW(WithinULP(1.f, 0));
|
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_THROWS_AS(WithinAbs(1., -1.), std::domain_error);
|
||||||
|
|
||||||
REQUIRE_NOTHROW(WithinULP(1., 0));
|
REQUIRE_NOTHROW(WithinULP(1., 0));
|
||||||
REQUIRE_THROWS_AS(WithinULP(1., -1), std::domain_error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user