diff --git a/tests/lib/cyclic-wrap-test.cpp b/tests/lib/cyclic-wrap-test.cpp index b52849128..1013e1346 100644 --- a/tests/lib/cyclic-wrap-test.cpp +++ b/tests/lib/cyclic-wrap-test.cpp @@ -19,21 +19,14 @@ #include "test/run.hpp" #include "lib/util-quant.hpp" #include "lib/util.hpp" -#include "test/diagnostic-output.hpp"//////////////////TODO -//#include "lib/format-cout.hpp" -//#include "lib/format-string.hpp" using ::Test; -//using util::isnil; -//using util::_Fmt; using util::isLimited; using std::floating_point; namespace util { namespace test { - - namespace{ // Test helpers... template @@ -49,6 +42,7 @@ namespace test { + /******************************************************************//** * @test Demonstrate and verify a cyclic wrapping numeric domain. * - show the wrapping behaviour with simple numbers @@ -56,7 +50,9 @@ namespace test { * - verify the computation works at the very bounds of the domain * - verify the most difficult path with a negative minVal, * and the smallest number in the domain - * @todo add coverage for floating-point numbers + * - show a similar simple wrapping behaviour with all float types + * - demonstrate the meaning of the precision limit + * - demonstrate aliasing and sanitised rounding errors * @see util::cyclicWrap * @see parameter-scale-test.cpp */ @@ -79,7 +75,9 @@ namespace test { verifyIntegerTypes (); verifyIntegerTypes(); - verifyFloatTypes(); + verifyFloatTypes(); + verifyFloatTypes(); + verifyFloatTypes(); } @@ -132,6 +130,8 @@ namespace test { CHECK (isLimited (LOWER, cyc(_MAX-1), UPPER)); CHECK (isLimited (LOWER, cyc(_MIN+1), UPPER)); + //------ Demonstrate behaviour at lower domain bound + // I dist = LOWER - _MIN; // guaranteed to be positive and representable in-domain I step = (dist / 5) * 5; // the next applicable grid point I excess = dist - step; @@ -140,96 +140,52 @@ namespace test { CHECK (LOWER + offset == cyc(_MIN) ); } + + template void verifyFloatTypes() { - double maxDom = _MAX; - double super = _MAX - _MIN; -SHOW_EXPR(maxDom) -SHOW_EXPR(super) -SHOW_EXPR(_EPS) -SHOW_EXPR(limit_cyclicWrap(1)) -SHOW_EXPR(limit_cyclicWrap(1024)) -SHOW_EXPR(limit_cyclicWrap(1.0/1024)) -SHOW_EXPR(limit_cyclicWrap(_EPS)) -SHOW_EXPR(limit_cyclicWrap(maxDom)) - - double limit5 = limit_cyclicWrap(5); - double atLimit = limit5 * (1-_EPS); - double stepLim = std::floor (limit5 / 5) * 5; -SHOW_EXPR(limit5*_EPS) -SHOW_EXPR(limit5) -SHOW_EXPR(stepLim) -SHOW_EXPR(atLimit) - -SHOW_EXPR(cyclicWrap (10.0 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (limit5 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (atLimit ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim-5 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+1 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+2 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+3 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+4 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+5 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+6 ,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+10,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+20,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+30,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+40,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+50,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+100,0.0, 5.0)) -SHOW_EXPR(cyclicWrap (stepLim+101,0.0, 5.0)) + auto cyc = [&](F val){ return cyclicWrap (val, F(-10),F(-5)); }; -SHOW_EXPL(cyclicWrap (limit5 ,10.0, 15.0)) -SHOW_EXPL(cyclicWrap (limit5+1 ,10.0, 15.0)) - double epsStep = _MAX*_EPS; - double toxicMin = _MIN + 2*epsStep; - double toxicMax = epsStep; - double toxicPeriod = toxicMax - toxicMin; -SHOW_EXPR(epsStep) -SHOW_EXPR(toxicMin) -SHOW_EXPR(toxicMax) -SHOW_EXPR(toxicPeriod) -SHOW_EXPR(cyclicWrap(0, toxicMin,toxicMax) ) -SHOW_EXPR(cyclicWrap(1, toxicMin,toxicMax) ) -SHOW_EXPR(cyclicWrap(1*epsStep, toxicMin,toxicMax) ) -SHOW_EXPR(cyclicWrap(2*epsStep, toxicMin,toxicMax) ) -SHOW_EXPR(cyclicWrap(3*epsStep, toxicMin,toxicMax) ) -SHOW_EXPR(cyclicWrap(0, 1, _MAX) ) -SHOW_EXPR(cyclicWrap(1, 1, _MAX) ) -SHOW_EXPR(cyclicWrap(2, 1, _MAX) ) -SHOW_EXPR(cyclicWrap(-1,1, _MAX) ) -SHOW_EXPR(cyclicWrap(-epsStep,1, _MAX) ) -SHOW_EXPR(1 == cyclicWrap(1, 1, _MAX)) -SHOW_EXPR(2 == cyclicWrap(2, 1, _MAX)) -SHOW_EXPR(1 == cyclicWrap(-1,1, _MAX) ) - double wrapped = cyclicWrap (-epsStep,double(1), _MAX); -SHOW_EXPR(1 < wrapped) -SHOW_EXPR(wrapped < _MAX) + CHECK (almostEqual (F(-10), cyc(0)) ); + CHECK (almostEqual (F( -9), cyc(1)) ); + CHECK (almostEqual (F( -8), cyc(2)) ); + CHECK (almostEqual (F( -7), cyc(3)) ); + CHECK (almostEqual (F( -6), cyc(4)) ); + CHECK (almostEqual (F(-10), cyc(5)) ); + CHECK (almostEqual (F( -9), cyc(6)) ); + CHECK (almostEqual (F( -8), cyc(7)) ); + CHECK (almostEqual (F( -7), cyc(8)) ); + CHECK (almostEqual (F( -6), cyc(9)) ); + CHECK (almostEqual (F(-10), cyc(105))); - auto cyc = [&](double val){ return cyclicWrap (val, double(-10),double(-5)); }; - - CHECK (almostEqual (double(-10), cyc(0))); - CHECK (almostEqual (double( -9), cyc(1))); - CHECK (almostEqual (double( -8), cyc(2))); - CHECK (almostEqual (double( -7), cyc(3))); - CHECK (almostEqual (double( -6), cyc(4))); - CHECK (almostEqual (double(-10), cyc(5))); - CHECK (almostEqual (double( -9), cyc(6))); - CHECK (almostEqual (double( -8), cyc(7))); - CHECK (almostEqual (double( -7), cyc(8))); - CHECK (almostEqual (double( -6), cyc(9))); - CHECK (almostEqual (double(-10), cyc(105))); + // For each period-length, a precision limit can be computed; + // whenever bounds or inputs approach that limit, the rounding errors + // approach the order of magnitude of the period-length, and thus + // computing of wrapped values becomes pointless... + F period5 = F(5); + F limit5 = limit_cyclicWrap (period5); - CHECK (almostEqual (double(5)/2, limit5 * _EPS)); + // one ULP-Step at the limit equals already half the period-length: + CHECK (almostEqual (period5/2, limit5 * _EPS)); + // so small steps will alias... CHECK (limit5 + 1 == limit5); - CHECK (1 == cyclicWrap( 1, 1,_MAX) ); - CHECK (2 == cyclicWrap( 2, 1,_MAX) ); - CHECK (1 == cyclicWrap(-1, 1,_MAX) ); - CHECK ( 1 < wrapped ); - CHECK (wrapped < _MAX); + // HOWEWER, very large periods can be handled (within numeric precision) + CHECK (1 == cyclicWrap( 1, 1,_MAX) ); + CHECK (2 == cyclicWrap( 2, 1,_MAX) ); // note: these values are *exact* -- due to std::fmod() + CHECK (3 == cyclicWrap( 3, 1,_MAX) ); + CHECK (4 == cyclicWrap( 4, 1,_MAX) ); + CHECK (5 == cyclicWrap( 5, 1,_MAX) ); + + CHECK (1 == cyclicWrap(-1, 1,_MAX) ); // yet this one gets aliased with the minVal + + F epsStep = _MAX*_EPS; + // yet the following input is clearly below minVal and will wrap upwards... + F wrapped = cyclicWrap (-epsStep, F(1),_MAX); + + CHECK ( 1 < wrapped); + CHECK (wrapped < _MAX); } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index adbfa8b6b..a2a3ea93e 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -86838,9 +86838,10 @@ Prop.1: dist%3 1 2 0 1 2 0 - - - + + + + @@ -86853,19 +86854,16 @@ Prop.1: dist%3 1 2 0 1 2 0 - - - +

.... ich könnte mir denken, daß mancher Leser das Konzept nicht gleich versteht, deshalb ist ein solches einfaches Beispiel nie verkehrt

- -
+
- + @@ -86888,6 +86886,120 @@ Prop.1: dist%3 1 2 0 1 2 0 + + + + + + + + +

+ ganz analog zum Integral-Fall +

+ +
+
+ + + + + + + + + + + + + +

+ die sollte dann aber nur für Input-Werte unterhalb des Limits funktionieren, allerdings auch negative Werte; oberhalb des Limits würde ich Entgleisungen vermuten +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Problem ist: hier kann ich kein »korrekt« oder »defekt« zeigen +

+ +
+ + + + + + + + + + + + + + + +

+ sobald man mit ε und ULPs hantiert, sind die numerischen Werte nur so minutiös verschieden, daß man es in der üblichen, gerundeten Darstellung gar nicht sieht. Damit scheiden alle Test-Methoden aus, die "einfache Zahlen" verwenden und ein festes Ergebnis vorgeben. Hinzu kommt, daß man auch einen ε-Vergleich machen muß, und dann ohne gesonderte Überlegung nicht offensichtlich ist, welche "Unschärfe" nun "unscharf" ist, und welche Teil des Test-Subjekts ist. Nicht daß man das alles irgendwie "hinbekommt" — aber der Leser versteht nicht mehr, was hier gespielt wird. +

+ +
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +