Lib: cover re-quantisation helper
...which I intend to use for sanitising poisonous rational numbers, as prerequisite for handling divisor based time scales in the ZoomWindow
This commit is contained in:
parent
ce1220ee72
commit
cfe3a6618f
3 changed files with 107 additions and 23 deletions
|
|
@ -97,6 +97,7 @@ namespace util {
|
|||
* in the same order of magnitude (which is surprising). This function gets
|
||||
* slightly faster for smaller data types. The naive bitshift-count implementation
|
||||
* is always significantly slower (8 times for int64_t, 1.6 times for int8_t)
|
||||
* @see Rational_test::verify_intLog2()
|
||||
* @see ZoomWindow_test
|
||||
*
|
||||
* [ToddLehman]: https://stackoverflow.com/users/267551/todd-lehman
|
||||
|
|
@ -155,17 +156,21 @@ namespace util {
|
|||
* causing numeric overflow when used, even just additively.
|
||||
* This function can thus be used to _"sanitise"_ a number,
|
||||
* and thus accept a small error while preventing overflow.
|
||||
* @note using extended-precision floating point to get close to the
|
||||
* quantiser even for large denominator. Some platforms
|
||||
* fall back to double, leading to extended error bounds
|
||||
*/
|
||||
inline Rat
|
||||
reQuant (Rat src, int64_t u)
|
||||
{
|
||||
int64_t d = rational_cast<int64_t> (src);
|
||||
int64_t r = src.numerator() % src.denominator();
|
||||
using f128 = long double;
|
||||
|
||||
// construct approximation quantised to 1/u
|
||||
double frac = rational_cast<double> (Rat{r, src.denominator()});
|
||||
f128 frac = rational_cast<f128> (Rat{r, src.denominator()});
|
||||
Rat res = d + int64_t(frac*u) / Rat(u);
|
||||
ENSURE (abs (rational_cast<double>(src) - rational_cast<double>(res)) < 1.0/abs(u));
|
||||
ENSURE (abs (rational_cast<f128>(src) - rational_cast<f128>(res)) <= 1.0/abs(u));
|
||||
return res;
|
||||
}
|
||||
} // namespace util
|
||||
|
|
|
|||
|
|
@ -28,15 +28,9 @@
|
|||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/format-obj.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
|
||||
#include "lib/rational.hpp"
|
||||
#include "lib/format-cout.hpp"//////////////TODO
|
||||
#define SHOW_TYPE(_TY_) \
|
||||
cout << "typeof( " << STRINGIFY(_TY_) << " )= " << lib::meta::typeStr<_TY_>() <<endl;
|
||||
#define SHOW_EXPR(_XX_) \
|
||||
cout << "#--◆--# " << STRINGIFY(_XX_) << " ? = " << _XX_ <<endl;
|
||||
//////////////////////////////////////////////////////////////////////////////TODO
|
||||
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
|
|
@ -194,7 +188,7 @@ namespace test {
|
|||
|
||||
|
||||
/**
|
||||
* @test a slightly optimised implementation of integer binary logarithm
|
||||
* @test an optimised implementation of integer binary logarithm
|
||||
* - basically finds the highest bit which is set
|
||||
* - can be used with various integral types
|
||||
* - performs better than using the floating-point solution
|
||||
|
|
@ -269,7 +263,7 @@ namespace test {
|
|||
array<uint64_t, 1000> numz;
|
||||
for (auto& n : numz)
|
||||
{
|
||||
n = rand() * uint64_t(2147483648);
|
||||
n = rand() * uint64_t(1 << 31);
|
||||
CHECK (ilog2(n) == floatLog(n));
|
||||
CHECK (ilog2(n) == bitshift(n));
|
||||
}
|
||||
|
|
@ -301,8 +295,8 @@ namespace test {
|
|||
<< "std::ilogb :"<<time_float<<"ns"<<endl
|
||||
<< "bit-shift :"<<time_shift<<"ns"<<endl
|
||||
<< "identity :"<<time_ident<<"ns"<<endl
|
||||
<< "(checksum="<<dump<<")" <<endl; // Warning: without outputting `dump`, compiler would optimise away most calls
|
||||
|
||||
<< "(checksum="<<dump<<")" <<endl; // Warning: without outputting `dump`,
|
||||
// the optimiser would eliminate most calls
|
||||
// the following holds both with -O0 and -O3
|
||||
CHECK (time_ilog2 < time_shift);
|
||||
CHECK (time_ident < time_ilog2);
|
||||
|
|
@ -335,7 +329,42 @@ namespace test {
|
|||
void
|
||||
verify_requant()
|
||||
{
|
||||
const int64_t MAX{std::numeric_limits<int64_t>::max()};
|
||||
const Rat MAXI = Rat{MAX};
|
||||
|
||||
Rat poison = (MAXI-88)/(MAXI/7);
|
||||
|
||||
auto approx = [](Rat rat){ return rational_cast<float> (rat); };
|
||||
CHECK (poison > 0);
|
||||
CHECK (poison+1 < 0); // wrap around!
|
||||
CHECK (approx (poison ) == 6.99999952f); // wildly wrong results...
|
||||
CHECK (approx (poison+1) == -6);
|
||||
CHECK (approx (poison+7) == -6.83047369e-17f);
|
||||
CHECK (approx (poison+9_r/5) == 0.400000006f);
|
||||
|
||||
Rat sleazy = reQuant (poison, 1 << 24); // recast into multiples of an arbitrary other divisor,
|
||||
CHECK (sleazy.denominator() == 1 << 24); // (here using a power of two as example)
|
||||
// and now we can do all the slick stuff...
|
||||
CHECK (sleazy > 0);
|
||||
CHECK (sleazy+1 > 0);
|
||||
CHECK (sleazy+7 > 0);
|
||||
CHECK (approx (sleazy) == 7);
|
||||
CHECK (approx (sleazy+1) == 8);
|
||||
CHECK (approx (sleazy+7) == 14);
|
||||
CHECK (approx (sleazy+9_r/5) == 8.80000019f);
|
||||
|
||||
CHECK (util::toString (poison) == "9223372036854775719/1317624576693539401sec");
|
||||
CHECK (util::toString (poison+1) =="-7905747460161236496/1317624576693539401sec");
|
||||
CHECK (util::toString (sleazy) == "117440511/16777216sec");
|
||||
CHECK (util::toString (sleazy+1) == "134217727/16777216sec");
|
||||
|
||||
// also works towards larger denominator, or with negative numbers...
|
||||
CHECK (reQuant (poison, MAX-7) == 104811045873349724_r/14973006553335675);
|
||||
CHECK (reQuant (-poison, 7777) == -54438_r/ 7777);
|
||||
CHECK (reQuant (poison, -7777) == -54438_r/-7777);
|
||||
|
||||
CHECK (approx (reQuant (poison, MAX-7)) == 7);
|
||||
CHECK (approx (reQuant (poison, 7777)) == 6.99987125f);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -39874,9 +39874,9 @@
|
|||
<linktarget COLOR="#784489" DESTINATION="ID_1438689210" ENDARROW="Default" ENDINCLINATION="202;-30;" ID="Arrow_ID_1396674797" SOURCE="ID_159285221" STARTARROW="None" STARTINCLINATION="-243;119;"/>
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1668295785449" ID="ID_248479209" MODIFIED="1668295794255" TEXT="Nenner gegen Limit prüfen"/>
|
||||
<node COLOR="#338800" CREATED="1668295795329" ID="ID_1179855526" MODIFIED="1668353517806" TEXT="Requantisieren">
|
||||
<node COLOR="#338800" CREATED="1668295795329" FOLDED="true" ID="ID_1179855526" MODIFIED="1668474431508" TEXT="Requantisieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1668353519645" ID="ID_1709187608" MODIFIED="1668353551219" TEXT="so exakt wie möglich">
|
||||
<node CREATED="1668353519645" ID="ID_1709187608" MODIFIED="1668474384018" TEXT="so exakt wie möglich">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -39887,17 +39887,20 @@
|
|||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<linktarget COLOR="#f2fbd7" DESTINATION="ID_1709187608" ENDARROW="Default" ENDINCLINATION="113;234;" ID="Arrow_ID_229027216" SOURCE="ID_505458679" STARTARROW="Default" STARTINCLINATION="-412;-14;"/>
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
</node>
|
||||
<node CREATED="1668353552561" ID="ID_1127388689" MODIFIED="1668353567293" TEXT="näherungsweise per double">
|
||||
<node COLOR="#435e98" CREATED="1668353552561" ID="ID_1127388689" MODIFIED="1668474254609" TEXT="näherungsweise per long double">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1668353569055" ID="ID_1784438485" MODIFIED="1668353581617" TEXT="aufteilen in Ganzzahl und Modulus"/>
|
||||
<node CREATED="1668353584405" ID="ID_1181209360" MODIFIED="1668353593384" TEXT="dann den Modulus näherungsweise requantifizieren"/>
|
||||
<node COLOR="#338800" CREATED="1668353653955" ID="ID_1020200002" MODIFIED="1668353816582" TEXT="Neben-Untersuchung: Ganzzahl-Zweierlogarithmus">
|
||||
<node COLOR="#338800" CREATED="1668353653955" FOLDED="true" ID="ID_1020200002" MODIFIED="1668353816582" TEXT="Neben-Untersuchung: Ganzzahl-Zweierlogarithmus">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1668353668892" ID="ID_259284183" MODIFIED="1668353679884" TEXT="ja... die banale Lösung mit der Bitshift-Schleife"/>
|
||||
<node CREATED="1668353680848" ID="ID_152151776" MODIFIED="1668353792957" TEXT="Geht das auch besser? vielleicht logarithmisch?">
|
||||
<node CREATED="1668353698198" ID="ID_394250867" LINK="https://stackoverflow.com/a/24748637" MODIFIED="1668353698198" TEXT="sowiso..."/>
|
||||
<node CREATED="1668353698198" ID="ID_394250867" LINK="https://stackoverflow.com/a/24748637" MODIFIED="1668353698198" TEXT="sowiso...">
|
||||
<linktarget COLOR="#ffe1c1" DESTINATION="ID_394250867" ENDARROW="Default" ENDINCLINATION="-128;27;" ID="Arrow_ID_791821354" SOURCE="ID_812438903" STARTARROW="None" STARTINCLINATION="-142;-24;"/>
|
||||
</node>
|
||||
<node CREATED="1668353698198" ID="ID_275694038" LINK="http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious" MODIFIED="1668353698198" TEXT="aber klar doch..."/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1668353793968" ID="ID_9788121" MODIFIED="1668353882082" TEXT="eine Adaption dieser Methode mal als Utility formuliert">
|
||||
|
|
@ -39940,6 +39943,7 @@
|
|||
<node CREATED="1668396009603" ID="ID_1438298126" MODIFIED="1668396019050" TEXT="für int64_t">
|
||||
<node CREATED="1668393519910" ID="ID_219605808" MODIFIED="1668397317940" TEXT="mein ilog2: 5.6ns"/>
|
||||
<node CREATED="1668393672305" ID="ID_812438903" MODIFIED="1668393802739" TEXT="Vorlage SO: 7.6ns">
|
||||
<arrowlink COLOR="#ffe1c1" DESTINATION="ID_394250867" ENDARROW="Default" ENDINCLINATION="-128;27;" ID="Arrow_ID_791821354" STARTARROW="None" STARTINCLINATION="-142;-24;"/>
|
||||
<node CREATED="1668395067578" ID="ID_386803191" MODIFIED="1668395176399" TEXT="das liegt aber nur am fehlenden -1 Branch">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
|
@ -40003,23 +40007,69 @@
|
|||
<node CREATED="1668353619784" ID="ID_395391770" MODIFIED="1668353624739" TEXT="nicht klar ob relevant"/>
|
||||
<node CREATED="1668353625375" ID="ID_27295187" MODIFIED="1668353643696" TEXT="dann auch Micro-Benchmark notwendig"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1668353892092" ID="ID_1654551581" MODIFIED="1668353948869" TEXT="Direkte Lösung + Fehler-Assert">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1668353892092" ID="ID_1654551581" MODIFIED="1668474307633" TEXT="Direkte Lösung + Fehler-Assert">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1668353919128" ID="ID_1237619949" MODIFIED="1668353937498" TEXT="ohne weitere Sanity-Checks"/>
|
||||
<node COLOR="#338800" CREATED="1668353938677" ID="ID_278768234" MODIFIED="1668353944961" TEXT="funktioniert im Smoke-Test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1668474259440" ID="ID_1390713963" MODIFIED="1668474302021" TEXT="verwende long double">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1668474283161" ID="ID_505458679" MODIFIED="1668474406928">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
damit kann ich stets so genau wie möglich rechnen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#f2fbd7" DESTINATION="ID_1709187608" ENDARROW="Default" ENDINCLINATION="113;234;" ID="Arrow_ID_229027216" STARTARROW="Default" STARTINCLINATION="-412;-14;"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1668474285441" ID="ID_318301259" MODIFIED="1668474305669" TEXT="Risiko: manche Plattformen definieren long double == double">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1668474317488" ID="ID_1121607924" MODIFIED="1668474342956" TEXT="erhöhe deshalb den Fehler-Assert auf einschlißlich Grenze">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1668353832314" ID="ID_1509712772" MODIFIED="1668353882082" TEXT="Test-Methoden ob ein Bruch »giftig« ist">
|
||||
<linktarget COLOR="#07a5b2" DESTINATION="ID_1509712772" ENDARROW="Default" ENDINCLINATION="96;-4;" ID="Arrow_ID_1066574831" SOURCE="ID_9788121" STARTARROW="None" STARTINCLINATION="-282;15;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1668354018194" HGAP="39" ID="ID_1484604434" MODIFIED="1668354032742" TEXT="Testabdeckung..." VSHIFT="14">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
<node COLOR="#338800" CREATED="1668354018194" HGAP="39" ID="ID_1484604434" MODIFIED="1668474197855" TEXT="Testabdeckung..." VSHIFT="14">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1668474155145" ID="ID_132764069" MODIFIED="1668474234849" TEXT="ein Beispiel mit Nenner nahe INT_MAX">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Rat poison = (MAXI-88)/(MAXI/7);
|
||||
</p>
|
||||
<p>
|
||||
...das ist näherungsweise Sieben...
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1668474201756" ID="ID_1997612449" MODIFIED="1668474234849" TEXT="Quantisieren auf feineren Divisor">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1668474224181" ID="ID_721417455" MODIFIED="1668474234849" TEXT="negative Zahlen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1668295799991" ID="ID_192811111" MODIFIED="1668295828000" TEXT="Zähler gegen Limit prüfen und ggfs kappen"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1668295799991" ID="ID_192811111" MODIFIED="1668474435369" TEXT="Zähler gegen Limit prüfen und ggfs kappen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue