catch_approx.cpp 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /*
  2. * Created by Martin on 19/07/2017.
  3. * Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
  4. *
  5. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. */
  8. #include "catch_approx.h"
  9. #include "catch_enforce.h"
  10. #include <cmath>
  11. #include <limits>
  12. namespace {
  13. // Performs equivalent check of std::fabs(lhs - rhs) <= margin
  14. // But without the subtraction to allow for INFINITY in comparison
  15. bool marginComparison(double lhs, double rhs, double margin) {
  16. return (lhs + margin >= rhs) && (rhs + margin >= lhs);
  17. }
  18. }
  19. namespace Catch {
  20. namespace Detail {
  21. Approx::Approx ( double value )
  22. : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
  23. m_margin( 0.0 ),
  24. m_scale( 0.0 ),
  25. m_value( value )
  26. {}
  27. Approx Approx::custom() {
  28. return Approx( 0 );
  29. }
  30. Approx Approx::operator-() const {
  31. auto temp(*this);
  32. temp.m_value = -temp.m_value;
  33. return temp;
  34. }
  35. std::string Approx::toString() const {
  36. ReusableStringStream rss;
  37. rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
  38. return rss.str();
  39. }
  40. bool Approx::equalityComparisonImpl(const double other) const {
  41. // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
  42. // Thanks to Richard Harris for his help refining the scaled margin value
  43. return marginComparison(m_value, other, m_margin)
  44. || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
  45. }
  46. void Approx::setMargin(double newMargin) {
  47. CATCH_ENFORCE(newMargin >= 0,
  48. "Invalid Approx::margin: " << newMargin << '.'
  49. << " Approx::Margin has to be non-negative.");
  50. m_margin = newMargin;
  51. }
  52. void Approx::setEpsilon(double newEpsilon) {
  53. CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
  54. "Invalid Approx::epsilon: " << newEpsilon << '.'
  55. << " Approx::epsilon has to be in [0, 1]");
  56. m_epsilon = newEpsilon;
  57. }
  58. } // end namespace Detail
  59. namespace literals {
  60. Detail::Approx operator "" _a(long double val) {
  61. return Detail::Approx(val);
  62. }
  63. Detail::Approx operator "" _a(unsigned long long val) {
  64. return Detail::Approx(val);
  65. }
  66. } // end namespace literals
  67. std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
  68. return value.toString();
  69. }
  70. } // end namespace Catch