Cleanup for floating point matchers

Removed the `Floating` nested namespace and added Doxygen comments
for the factory methods.
This commit is contained in:
Martin Hořeňovský 2020-03-28 12:48:19 +01:00
parent a6baa6dda6
commit afc8b28c07
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
2 changed files with 71 additions and 71 deletions

View File

@ -99,13 +99,15 @@ void write(std::ostream& out, FloatingPoint num) {
} // end anonymous namespace } // end anonymous namespace
namespace Matchers { namespace Matchers {
namespace Floating { namespace Detail {
enum class FloatingPointKind : uint8_t { enum class FloatingPointKind : uint8_t {
Float, Float,
Double Double
}; };
} // end namespace Detail
WithinAbsMatcher::WithinAbsMatcher(double target, double margin) WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
:m_target{ target }, m_margin{ margin } { :m_target{ target }, m_margin{ margin } {
@ -124,9 +126,9 @@ namespace Floating {
} }
WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType) WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, Detail::FloatingPointKind baseType)
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
CATCH_ENFORCE(m_type == FloatingPointKind::Double CATCH_ENFORCE(m_type == Detail::FloatingPointKind::Double
|| m_ulps < (std::numeric_limits<uint32_t>::max)(), || m_ulps < (std::numeric_limits<uint32_t>::max)(),
"Provided ULP is impossibly large for a float comparison."); "Provided ULP is impossibly large for a float comparison.");
} }
@ -139,12 +141,12 @@ namespace Floating {
bool WithinUlpsMatcher::match(double const& matchee) const { bool WithinUlpsMatcher::match(double const& matchee) const {
switch (m_type) { switch (m_type) {
case FloatingPointKind::Float: case Detail::FloatingPointKind::Float:
return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps); return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
case FloatingPointKind::Double: case Detail::FloatingPointKind::Double:
return almostEqualUlps<double>(matchee, m_target, m_ulps); return almostEqualUlps<double>(matchee, m_target, m_ulps);
default: default:
CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); CATCH_INTERNAL_ERROR( "Unknown Detail::FloatingPointKind value" );
} }
} }
@ -157,7 +159,7 @@ namespace Floating {
ret << "is within " << m_ulps << " ULPs of "; ret << "is within " << m_ulps << " ULPs of ";
if (m_type == FloatingPointKind::Float) { if (m_type == Detail::FloatingPointKind::Float) {
write(ret, static_cast<float>(m_target)); write(ret, static_cast<float>(m_target));
ret << 'f'; ret << 'f';
} else { } else {
@ -165,7 +167,7 @@ namespace Floating {
} }
ret << " (["; ret << " ([";
if (m_type == FloatingPointKind::Double) { if (m_type == Detail::FloatingPointKind::Double) {
write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps)); write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));
ret << ", "; ret << ", ";
write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps)); write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));
@ -199,39 +201,35 @@ namespace Floating {
return sstr.str(); return sstr.str();
} }
}// namespace Floating
WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Double);
Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
} }
Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Float);
} }
Floating::WithinAbsMatcher WithinAbs(double target, double margin) { WithinAbsMatcher WithinAbs(double target, double margin) {
return Floating::WithinAbsMatcher(target, margin); return WithinAbsMatcher(target, margin);
} }
Floating::WithinRelMatcher WithinRel(double target, double eps) { WithinRelMatcher WithinRel(double target, double eps) {
return Floating::WithinRelMatcher(target, eps); return WithinRelMatcher(target, eps);
} }
Floating::WithinRelMatcher WithinRel(double target) { WithinRelMatcher WithinRel(double target) {
return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100); return WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
} }
Floating::WithinRelMatcher WithinRel(float target, float eps) { WithinRelMatcher WithinRel(float target, float eps) {
return Floating::WithinRelMatcher(target, eps); return WithinRelMatcher(target, eps);
} }
Floating::WithinRelMatcher WithinRel(float target) { WithinRelMatcher WithinRel(float target) {
return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100); return WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
} }
} // namespace Matchers } // namespace Matchers
} // namespace Catch } // namespace Catch

View File

@ -12,57 +12,59 @@
namespace Catch { namespace Catch {
namespace Matchers { namespace Matchers {
namespace Floating { namespace Detail {
enum class FloatingPointKind : uint8_t; enum class FloatingPointKind : uint8_t;
}
struct WithinAbsMatcher final : MatcherBase<double> { struct WithinAbsMatcher final : MatcherBase<double> {
WithinAbsMatcher(double target, double margin); WithinAbsMatcher(double target, double margin);
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;
double m_margin; double m_margin;
}; };
struct WithinUlpsMatcher final : MatcherBase<double> { struct WithinUlpsMatcher final : MatcherBase<double> {
WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType); WithinUlpsMatcher(double target, uint64_t ulps, Detail::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;
uint64_t m_ulps; uint64_t m_ulps;
FloatingPointKind m_type; Detail::FloatingPointKind m_type;
}; };
// Given IEEE-754 format for floats and doubles, we can assume // Given IEEE-754 format for floats and doubles, we can assume
// that float -> double promotion is lossless. Given this, we can // that float -> double promotion is lossless. Given this, we can
// assume that if we do the standard relative comparison of // assume that if we do the standard relative comparison of
// |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
// the same result if we do this for floats, as if we do this for // the same result if we do this for floats, as if we do this for
// doubles that were promoted from floats. // doubles that were promoted from floats.
struct WithinRelMatcher final : MatcherBase<double> { struct WithinRelMatcher final : MatcherBase<double> {
WithinRelMatcher(double target, double epsilon); WithinRelMatcher(double target, double epsilon);
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;
double m_epsilon; double m_epsilon;
}; };
} // namespace Floating //! Creates a matcher that accepts doubles within certain ULP range of target
WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts floats within certain ULP range of target
WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
//! Creates a matcher that accepts numbers within certain range of target
WithinAbsMatcher WithinAbs(double target, double margin);
// The following functions create the actual matcher objects. //! Creates a matcher that accepts doubles within certain relative range of target
// This allows the types to be inferred WithinRelMatcher WithinRel(double target, double eps);
Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); //! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); WithinRelMatcher WithinRel(double target);
Floating::WithinAbsMatcher WithinAbs(double target, double margin); //! Creates a matcher that accepts doubles within certain relative range of target
Floating::WithinRelMatcher WithinRel(double target, double eps); WithinRelMatcher WithinRel(float target, float eps);
// defaults epsilon to 100*numeric_limits<double>::epsilon() //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
Floating::WithinRelMatcher WithinRel(double target); WithinRelMatcher WithinRel(float target);
Floating::WithinRelMatcher WithinRel(float target, float eps);
// defaults epsilon to 100*numeric_limits<float>::epsilon()
Floating::WithinRelMatcher WithinRel(float target);
} // namespace Matchers } // namespace Matchers
} // namespace Catch } // namespace Catch