Parameters: document and verify integration into cyclic Scale
- verify using an unsigned integer, for a typical ''angle scale'' - also verify a high-res floating-point scale, and demonstrate rounding issues
This commit is contained in:
parent
eef5ddef0e
commit
30636b3253
5 changed files with 136 additions and 17 deletions
|
|
@ -119,7 +119,9 @@ namespace par {
|
|||
)
|
||||
)
|
||||
and (not isCyclic()
|
||||
or (minVal and maxVal and *minVal < *maxVal)
|
||||
or (minVal and maxVal
|
||||
and *minVal < *maxVal
|
||||
and VAL(0) < cyclicLim)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
|
@ -169,8 +171,8 @@ namespace par {
|
|||
if (std::is_floating_point_v<VAL>)
|
||||
if (not (std::abs (rawVal) < cyclicLim))
|
||||
throw err::Invalid {util::_Fmt{"Parameter value %4.2g beyond supported numeric precision "
|
||||
"for cyclic wrapping into (%4.2g ... %4.2g("}
|
||||
% rawVal % minVal % maxVal
|
||||
"for cyclic wrapping into [%1.2g...%1.2g[ "}
|
||||
% rawVal % *minVal % *maxVal
|
||||
};
|
||||
return util::cyclicWrap (rawVal, *minVal, *maxVal);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "lib/random.hpp"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <concepts>
|
||||
#include <typeinfo>
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
|
@ -61,14 +62,15 @@ namespace test{
|
|||
using util::showType;
|
||||
using util::showTypes;
|
||||
|
||||
using std::floating_point;
|
||||
|
||||
constexpr auto ROUGH_PRECISION = pow (10, -3);
|
||||
constexpr auto EPSILON_ULP = 5;
|
||||
|
||||
|
||||
template<typename F, typename N>
|
||||
constexpr inline enable_if< std::is_floating_point<F>,
|
||||
bool >
|
||||
template<floating_point F, typename N>
|
||||
constexpr inline
|
||||
bool
|
||||
roughEQ (F val, N target, F limit =ROUGH_PRECISION)
|
||||
{
|
||||
REQUIRE (0 < limit);
|
||||
|
|
@ -76,9 +78,9 @@ namespace test{
|
|||
} //////////////////////////////////////////////////////////////////////////TICKET #1360 looks like this problem was solved several times
|
||||
|
||||
|
||||
template<typename F>
|
||||
constexpr inline enable_if< std::is_floating_point<F>,
|
||||
F >
|
||||
template<floating_point F>
|
||||
constexpr inline
|
||||
F
|
||||
ulp (F val)
|
||||
{
|
||||
val = fabs (val);
|
||||
|
|
@ -90,9 +92,9 @@ namespace test{
|
|||
return scaledUlp;
|
||||
}
|
||||
|
||||
template<typename F, typename N>
|
||||
constexpr inline enable_if< std::is_floating_point<F>,
|
||||
bool >
|
||||
template<floating_point F, typename N>
|
||||
constexpr inline
|
||||
bool
|
||||
epsEQ (F val, N target, uint ulps =EPSILON_ULP)
|
||||
{
|
||||
return abs (val - target) < ulps * ulp<F> (target);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "lib/util-quant.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
using ::Test;
|
||||
using util::isLimited;
|
||||
using std::floating_point;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
|
||||
#include "test/run.hpp"
|
||||
//#include "test/test-helper.hpp"
|
||||
#include "test/test-helper.hpp"
|
||||
#include "lib/par/scale.hpp"
|
||||
#include "test/diagnostic-output.hpp"/////////////TODO
|
||||
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
//using std::string;
|
||||
//using std::vector;
|
||||
//using std::swap;
|
||||
using test::roughEQ;
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -59,6 +60,7 @@ namespace test{
|
|||
{
|
||||
simpleUsage();
|
||||
verify_Conforming();
|
||||
verify_cyclicScale();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -76,8 +78,10 @@ namespace test{
|
|||
}
|
||||
|
||||
|
||||
/** @test
|
||||
* @todo WIP 9/26 🔁 define ⟶ implement
|
||||
/** @test accommodate values to comply with the scale
|
||||
* - optionally a maximum and minimum can be enforced
|
||||
* - optionally the value can be cyclically wrapped
|
||||
* @todo WIP 9/26 ✔ define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
verify_Conforming()
|
||||
|
|
@ -87,7 +91,79 @@ namespace test{
|
|||
|
||||
scale.maxVal = -5.0f;
|
||||
CHECK (-5.0f == scale.conform (1e5f));
|
||||
|
||||
CHECK (scale.isValid());
|
||||
scale.minVal = 5.0f;
|
||||
CHECK (not scale.isValid());
|
||||
scale.maxVal = 8.0f;
|
||||
CHECK (scale.isValid());
|
||||
CHECK (5.0f == scale.conform (-5.0f));
|
||||
|
||||
CHECK (not scale.isCyclic());
|
||||
scale.cyclicLim = 100;
|
||||
CHECK (scale.isCyclic());
|
||||
CHECK (7.0f == scale.conform (-5.0f));
|
||||
CHECK (5.0f == scale.conform (-4.0f));
|
||||
CHECK (6.0f == scale.conform (-3.0f));
|
||||
CHECK (7.0f == scale.conform (-2.0f));
|
||||
|
||||
VERIFY_FAIL ("beyond supported numeric precision"
|
||||
, scale.conform (-1e5f));
|
||||
}
|
||||
|
||||
|
||||
/** @test Scales can be configured to wrap cyclically, e.g. for angles.
|
||||
* - demonstrate an unsigned angle scale with short precision
|
||||
* - demonstrate a high-resolution scale symmetric to zero
|
||||
* @todo WIP 9/26 ✔define ⟶ 🔁 implement
|
||||
*/
|
||||
void
|
||||
verify_cyclicScale()
|
||||
{
|
||||
Scale<ushort> angleScale = {.minVal=0, .maxVal=360, .cyclicLim=0xFFFF};
|
||||
CHECK (angleScale.isValid());
|
||||
CHECK (angleScale.isCyclic());
|
||||
|
||||
CHECK ( 0 == angleScale.conform(0));
|
||||
CHECK (180 == angleScale.conform(180));
|
||||
CHECK (240 == angleScale.conform(240));
|
||||
CHECK ( 0 == angleScale.conform(360));
|
||||
CHECK (359 == angleScale.conform(719));
|
||||
CHECK ( 0 == angleScale.conform(65520));
|
||||
CHECK ( 15 == angleScale.conform(65535));
|
||||
|
||||
|
||||
Scale<f128> tinyScale = {.minVal=-f128(1)/100, .maxVal=f128(1)/100};
|
||||
tinyScale.cyclicLim = util::limit_cyclicWrap(*tinyScale.maxVal - *tinyScale.minVal);
|
||||
CHECK (1e16 < tinyScale.cyclicLim);
|
||||
CHECK (tinyScale.isValid());
|
||||
CHECK (tinyScale.isCyclic());
|
||||
|
||||
CHECK ( tinyScale.conform(0 ) == 0 );
|
||||
CHECK (roughEQ (tinyScale.conform(0.001) , 0.001));
|
||||
CHECK (roughEQ (tinyScale.conform(0.005) , 0.005));
|
||||
CHECK (roughEQ (tinyScale.conform(0.00999), 0.00999));
|
||||
CHECK (roughEQ (tinyScale.conform(0.01 ),-0.0099999)); // surprise: 1/100 not exactly representable in floating-point
|
||||
|
||||
// since the domain is symmetric and 2/100 long, the ten-folds will fall into the middle,
|
||||
// but they typically do not land precisely on zero due to inherent "number dust"
|
||||
CHECK (1e15 > fabs(tinyScale.conform(1)));
|
||||
CHECK (0 != tinyScale.conform(1) );
|
||||
|
||||
auto beyond_precision = -10 * tinyScale.cyclicLim;
|
||||
VERIFY_FAIL ("beyond supported numeric precision"
|
||||
, tinyScale.conform (beyond_precision));
|
||||
}
|
||||
|
||||
|
||||
/** @test
|
||||
* @todo WIP 9/26 🔁 define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_valueJoining()
|
||||
{
|
||||
Scale<float> scale;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -87231,7 +87231,7 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789159639409" ID="ID_654373559" MODIFIED="1789159678163" TEXT="Scale-Eigenschaften abstecken per ParameterScale_test">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789159639409" ID="ID_654373559" MODIFIED="1789607860036" TEXT="Scale-Eigenschaften abstecken per ParameterScale_test">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1789159687318" ID="ID_1480074646" MODIFIED="1789160197623" TEXT="Hier nur rein die Scale-Descriptoren und das intendierte Verhalten">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -87260,6 +87260,46 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789607293094" ID="ID_734632281" MODIFIED="1789607296849" TEXT="verify_Conforming">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1789607298013" ID="ID_452068382" MODIFIED="1789607555871" TEXT="im Grunde offensichtlich und redundant">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...da ein Test eigentlich mehr machen sollte, als nur nochmal den Code zu wiederholen; und hier passiert nicht mehr, als ein cap an der boundrary, auf einem komplett offensichtlichen und einfachen Code-Pfad
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1789607312019" ID="ID_1154758301" MODIFIED="1789607325207" TEXT="aber man könnte einen anderen Datentyp testen (z.B. Float)"/>
|
||||
<node CREATED="1789607333006" ID="ID_1782430086" MODIFIED="1789607343123" TEXT="und zeigen daß auch das cyclicWrap hier integriert ist"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789607351998" ID="ID_144363848" MODIFIED="1789607354317" TEXT="verify_cyclicScale">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1789607356261" ID="ID_1762601340" MODIFIED="1789607743052" TEXT="auch hier nur bedingt sinnvoll testbar">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...denn die eigentlich trickreiche Funktionalität steckt in der Library-Funktion und ist dort schon per Unit-Test abgedeckt, und das korrekte Setup wird innerhalb des Scale-Descriptors gar nicht geprüft (weil diese Prüfung in den umschließenden Kontext gehört, wo die Scale in einen Parameter-Typ eingebunden wird)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1789607368451" ID="ID_383818308" MODIFIED="1789607375932" TEXT="kann zwei relevante Fälle demonstrieren">
|
||||
<node CREATED="1789607377402" ID="ID_1342839519" MODIFIED="1789607401203" TEXT="Winkel-Skala (unsigned short)"/>
|
||||
<node CREATED="1789607407654" ID="ID_1837015555" MODIFIED="1789607428439" TEXT="floating-point-Scala mit kleinen Werten"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1789607809345" ID="ID_1668358580" MODIFIED="1789607849725" TEXT="diese Tests dienen eigentlich nur dem Integrations-Check — und sind Dokumentation">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue