@@ -14,15 +14,15 @@ private noreturn assumeAllAttrAndCall(scope const void delegate() t)
1414}
1515
1616// /
17- struct ShouldApprox (T)
18- if (__traits(isFloating, T))
17+ struct ShouldApprox (T, F = T )
18+ if (( __traits(isFloating, T) || __traits(hasMember, T, "approxEqual")) && __traits(isFloating, F ))
1919{
2020 // /
2121 T value;
2222 // /
23- T maxRelDiff = 0x1p- 20f ;
23+ F maxRelDiff = 0x1p- 20f ;
2424 // /
25- T maxAbsDiff = 0x1p- 20f ;
25+ F maxAbsDiff = 0x1p- 20f ;
2626
2727 // /
2828 void opEquals (T expected, string file = __FILE__ , int line = __LINE__ ) @safe pure nothrow @nogc
@@ -59,6 +59,28 @@ unittest
5959 shouldApprox(1 + 9e-7 , 1e-6 , 1e-6 ) == 1 ;
6060}
6161
62+ // / ditto
63+ ShouldApprox! (T, F) shouldApprox(T, F)(const T value, const F maxRelDiff = double (0x1p- 20f ), const F maxAbsDiff = double (0x1p- 20f ))
64+ if (__traits(hasMember, T, " approxEqual" ) && __traits(isFloating, F))
65+ {
66+ return typeof (return )(value, maxRelDiff, maxAbsDiff);
67+ }
68+
69+ // /
70+ version (mir_test)
71+ unittest
72+ {
73+ static struct C {
74+ double re, im;
75+ auto approxEqual (C rhs, double maxRelDiff, double maxAbsDiff)
76+ {
77+ import mir.math.common: approxEqual;
78+ return approxEqual (re, rhs.re, maxRelDiff, maxAbsDiff) && approxEqual(im, rhs.im, maxRelDiff, maxAbsDiff);
79+ }
80+ }
81+ C(1.0 , 1.0 ).shouldApprox == C(1 + 9e-7 , 1 - 9e-7 );
82+ }
83+
6284// /
6385struct Should (T)
6486{
0 commit comments