diff --git a/src/lib/par/domain.hpp b/src/lib/par/domain.hpp index 419a24a32..1371b8ceb 100644 --- a/src/lib/par/domain.hpp +++ b/src/lib/par/domain.hpp @@ -47,6 +47,7 @@ namespace lib { namespace par { + using util::isNeg; using std::same_as; using std::floating_point; using std::numeric_limits; @@ -177,15 +178,8 @@ _Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"") or std::numeric_limits::max() < std::numeric_limits::max() or std::numeric_limits::lowest() > std::numeric_limits::lowest() ; - - template - inline constexpr bool - isNeg (NUM const& num) - { - return num < NUM(0); - }; - - + + _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wsign-compare\"") // the following functions are specifically crafted to work around diff --git a/src/lib/util.hpp b/src/lib/util.hpp index 02f22e198..e5b2618e5 100644 --- a/src/lib/util.hpp +++ b/src/lib/util.hpp @@ -60,7 +60,9 @@ namespace util { inline constexpr int sgn (NUM n) { - return (n==0)? 0 :((n<0)? -1:+1 ); + return n== NUM{0}? 0 + : n < NUM{0}? -1 + : +1; } template @@ -77,12 +79,20 @@ namespace util { return n1 < n2? N1(n2) : n1; } + /** @remark safe to use also on unsigned */ + template + inline constexpr bool + isNeg (NUM const& num) + { + return num < NUM{0}; + }; + /** cut a numeric value to be >=0 */ template inline constexpr NUM noneg (NUM val) { - return (0 //#include //#include +#include //using std::string; //using std::vector; @@ -35,20 +36,19 @@ namespace par { namespace test{ // using lumiera::error::LUMIERA_ERROR_LOGIC; + using std::floating_point; namespace {//Test fixture.... - class Thing - { }; + template + constexpr NUM _MAX = std::numeric_limits::max(); - template - struct Some - { - X x; - }; + template + constexpr NUM _MIN = std::numeric_limits::lowest(); + + template + constexpr FLO _EPSILON = std::numeric_limits::epsilon(); - typedef Some SomeThing; - }//(End)Test fixture @@ -69,6 +69,7 @@ namespace test{ run (Arg) { seedRand(); + basics(); verify_valueLimits(); verify_valueAccess(); @@ -81,37 +82,93 @@ namespace test{ } + /** @test base operation to bracket a given value + * so that it fits within another target type's value domain. + * @note properly handles the signed vs. unsigned mismatch, so that + * conversion from signed to unsigned can not wrap. + */ void verify_valueLimits() { -SHOW_EXPR(preClamp (23)) -SHOW_EXPR(preClamp (-55)) -SHOW_EXPR(preClamp (23)) -SHOW_EXPR(preClamp (-55)) -SHOW_EXPR((sub_domain)) -SHOW_EXPR((sub_domain)) -SHOW_EXPR((sub_domain)) -SHOW_EXPR((sub_domain)) -SHOW_EXPR(std::numeric_limits::max()) -SHOW_EXPR(std::numeric_limits::max()) -SHOW_EXPR(std::numeric_limits::lowest()) -SHOW_EXPR(std::numeric_limits::lowest()) + // Generic check if the first (target) type can hold + // only a limited part of the second (source) type's domain + CHECK ((sub_domain == true)); + CHECK ((sub_domain == true)); + CHECK ((sub_domain == true)); + CHECK ((sub_domain == false)); + CHECK ((sub_domain == true)); + CHECK ((sub_domain == false)); + + // Limit a value to within a target type's domain + // (without actually converting into the target type) + CHECK (preClamp (23) == 23); + CHECK (preClamp (-55) == -55); + CHECK (preClamp (23) == 23); + CHECK (preClamp(-55) == 0); -SHOW_EXPR(preClamp (INT64_MAX)) -SHOW_EXPR(preClamp (INT64_MIN)) + CHECK (preClamp (_MAX) == 32767); + CHECK (preClamp (_MIN) == -32768); + + CHECK (preClamp (_MAX) == 65535); + CHECK (preClamp (_MIN) == 0 ); + + // the return value has the same type as the argument... + CHECK (preClamp (_MAX) == _MAX); + CHECK (preClamp (_MIN) == double(_MIN) ); + + // Warning: the following is not standard C++, yet supported on GCC / CLang / libstdc++ + static_assert (_MAX < _MAX); + CHECK (float(_MAX) == "inf"_expect ); + CHECK ((unsigned __int128)_MAX == "340282346638528859811704183484516925440"_expect ); + + CHECK (preClamp (_MAX) == (unsigned __int128)_MAX); -SHOW_EXPR(preClamp (numeric_limits::max())) -SHOW_EXPR(preClamp (numeric_limits::lowest())) + // Note: a trigger at 0.5+ε is built into the clamp towards bool + CHECK (preClamp (0.5) == 0 ); + CHECK (preClamp (0.5+_EPSILON) == 1 ); + CHECK (preClamp (_MIN) == 0 ); + + + // Systematic coverage of signed ⟷ unsigned + CHECK (preClamp (_MAX) == 127); + CHECK (preClamp ( int16_t{0}) == 0); + CHECK (preClamp (_MIN) == -128); -SHOW_EXPR(preClamp (numeric_limits::max())) -SHOW_EXPR(preClamp (numeric_limits::lowest())) + CHECK (preClamp (_MAX) == 127); + CHECK (preClamp (_MIN) == 0); -SHOW_EXPR(preClamp (0.5)); -SHOW_EXPR(preClamp (0.5 + numeric_limits::epsilon())) -SHOW_EXPR(preClamp (numeric_limits::min())) + CHECK (preClamp (_MAX) == 255); + CHECK (preClamp ( int16_t{0}) == 0); + CHECK (preClamp (_MIN) == 0); + + CHECK (preClamp (_MAX) == 127); + CHECK (preClamp ( int8_t{0}) == 0); + CHECK (preClamp (_MIN) == -128); + + CHECK (preClamp (_MAX) == 255); + CHECK (preClamp (_MIN) == 0); + + CHECK (preClamp (_MAX) == 127); + CHECK (preClamp ( int8_t{0}) == 0); + CHECK (preClamp (_MIN) == 0); + + CHECK (preClamp (_MAX) == 127); + CHECK (preClamp ( int8_t{0}) == 0); + CHECK (preClamp (_MIN) == -128); + + CHECK (preClamp (_MAX) == 127); + CHECK (preClamp (_MIN) == 0); + + CHECK (preClamp (_MAX) == 127); + CHECK (preClamp ( int8_t{0}) == 0); + CHECK (preClamp (_MIN) == 0); } + + /** @test base function to access the contents of an opaque buffer + * with known type, and convert into another target type. + */ void verify_valueAccess() { @@ -133,6 +190,13 @@ SHOW_EXPR(preClamp (numeric_limits::min())) TypeHandler& df1{d1}; df1.extractAs (target2, src1); CHECK (target2 == float(val1)); + + // value clamped to target domain... + val1 = _MIN; + uint64_t target3{55}; + TypeHandler& du64{d1}; + du64.extractAs (target3, src1); + CHECK (target3 == _MIN); } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 94b0d7efd..0539d46aa 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -83122,16 +83122,32 @@ - - + + + - - + + + + + + +

+ aber signed vs. unsigned- Werte lassen sich +

+

+ gar nicht so ohne Weiteres vergleichen +

+ + +
+ - + + @@ -83341,13 +83357,12 @@ }

- -
+
- + @@ -83356,8 +83371,7 @@ Unter der Annahme, daß lediglich die signed/unsigned Integers das Problem sind; denn für jeden Integer-Typ kann man val < TY(0) bilden

- -
+ @@ -83367,8 +83381,7 @@ die Funktion "noneg()" macht den Verlgeich genau falsch herum:  0 < uint(-1) ⟹ true

- -
+
@@ -83381,8 +83394,7 @@ hier hilft uns die automatische Promotion in den Typ mit dem höheren Rank: nur deshalb können wir die Vergleichsoperation machen. Zudem kann der Verleich im negativen Segment überhaupt nur stattfinden, wenn beide Typen negativ sind, also mithin signed

- - +
@@ -83398,16 +83410,34 @@
+ + + + + + + + + + + + + + + + + + - + @@ -83416,7 +83446,7 @@

- +
@@ -83433,7 +83463,7 @@
- + @@ -83442,6 +83472,7 @@

+
@@ -83510,8 +83541,7 @@ - - + @@ -83521,8 +83551,7 @@ Im ersten Entwurf habe ich die unterliegenden Typen einfach in eine Typelist gepackt. Die Analyse zeigte ganz klar, daß diese Menge der Basiswerte bereits zur Compile-time festgelegt sein muß, sonst tun sich ganz ekelhafte Probleme auf mit Registrierung und Locking im Zusammenhang mit dem Laden von dynamischen Objekten (Plug-ins)....

- -
+
@@ -83532,8 +83561,7 @@ Ein billiger Ansatz wäre, das Thema zu ignorieren, und solche Parameter einfach als eine Gruppe von Einzelparametern zu behandeln. Das wäre angemessen, wenn man das als Randthema betrachtet. Gegen diesen Ansatz spricht, daß man an einen Farbwert auch eine Kalibrierungskurve und einen Farbraum anhängen möchte, sonst wird Arbeiten mit professionellen Medien-Produktionsprozessen (HDR, Grading, Mastering) praktisch unmöglich. Auch an verschiedene Spielarten von »3D« sollte man denken, incl. virtueller Projektionsräume. Ein MIttelweg wäre, daß man Parameter-Tupel unterstützt, denen Metadaten angehängt werden

- -
+
@@ -83543,8 +83571,7 @@ ....zunächst einmal sind das Produkttypen, aber mit einer hohen Kardinalität. Das Konzept der Shape-Keys reduziert das wieder auf eine Achse, auf der man einen Kontrollparameter animieren kann. Bei Masken besteht das zusätzliche (in der Praxis sehr relevante) Problem, daß »unterwegs« weitere Maskenpunkte dazukommen können, und daß einzelne Maskenpunkte noch weitere Parameter tragen können, wie z.B. eine feather-strength, was extrem wichtig ist für Rotoscoping.

- -
+