Current implementation of std.math.approxEqual is not symmetric. The code below gives an example.
import std.math : eq = approxEqual;
immutable real
a = (2e-3)-(1e-5),
b = (2e-3)+(1e-5);
assert ( a.eq(b)); // (error relative to b) = 1 / (100.5)
assert (!b.eq(a)); // (error relative to a) = 1 / ( 99.5)
IMO at least we need to document this. It may be enough since the case this asymmetricity do something harm is rare.
If we "fix" it, we must consider the backward compatibility, and/or performance.
I would be pleased with an alternative for approxEqual like this:
return ((a - b).abs < abserr) || ((a - b).abs / (a.abs + b.abs) < relerr / 2);
Any opinion?
Comment #1 by schveiguy — 2017-03-31T23:50:20Z
I think that you need to pick one of the two parameters to determine the relative error.
One could use a some test to determine the "best" value, but "best" is subjective. Armed with the knowledge that the second parameter is the one that is the basis for the percentage difference, you can call it in the correct order.
Working on Doc PR.
Comment #2 by schveiguy — 2017-04-01T00:23:04Z
Hm... also found an issue, because if rhs is a range, but lhs is a value, it swaps the arguments and calls approxEqual(rhs, lhs). Clearly, if rhs is the relative difference determination, you don't want to do this (as the comparison isn't symmetrical).
PR: https://github.com/dlang/phobos/pull/5316
Comment #3 by github-bugzilla — 2017-04-10T14:36:56Z