-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Approx is not symmetric #1746
Comments
Yes, it is not symmetric and currently that is the intended behaviour. This is expected to be less surprising to people with only a fuzzy If you want something that is scale and order independent, you can |
This is disappointing. I'm not sure what purpose you were trying to achieve by trying to explain with an example that is essentially the same as the one that I gave, except that it is scaled up by a factor of 10. What do you consider will be user's expectations when the arguments to Approx are variables rather than literals?
|
I would still expect the user's expectation to be "is Anyway,
|
It checks Knuth's _close enough with tolerance_ relationship, that is `|lhs - rhs| <= epsilon * max(|lhs|, |rhs|)`, rather then the _very close with tolerance_ relationship that can be written down as `|lhs - rhs| <= epsilon * min(|lhs|, |rhs|)`. This is because it is the more common model around the internet, and as such is likely to be less surprising to the users. In the future we might want to provide the other model as well. Closes catchorg#1746
Describe the bug
For certain values, Approx does not exhibit symmetric behaviour. That is, it is possible that Approx(a) == b but Approx(b) != a.
This can occur when b ~= a(1 + epsilon)
Expected behavior
The same result should be produced irrespective of whether 2 values are on the left or right.
Reproduction steps
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
TEST_CASE( "Approx is symmetric", "[approx]" )
{
Approx target1 = Approx(1.0).epsilon(0.1);
Approx target2 = Approx(1.105).epsilon(0.1);
REQUIRE((target1 == 1.105) == (target2 == 1.0));
}
Platform information:
Additional context
The following change should fix this issue (using std::max for the two values).
bool Approx::equalityComparisonImpl(const double other) const {
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
// Thanks to Richard Harris for his help refining the scaled margin value
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::max(std::fabs(other), std::fabs(m_value))));
}
The text was updated successfully, but these errors were encountered: