diff --git a/src/lib/rational.hpp b/src/lib/rational.hpp index aba71c3cf..9fbe260e6 100644 --- a/src/lib/rational.hpp +++ b/src/lib/rational.hpp @@ -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 (src); int64_t r = src.numerator() % src.denominator(); + using f128 = long double; // construct approximation quantised to 1/u - double frac = rational_cast (Rat{r, src.denominator()}); + f128 frac = rational_cast (Rat{r, src.denominator()}); Rat res = d + int64_t(frac*u) / Rat(u); - ENSURE (abs (rational_cast(src) - rational_cast(res)) < 1.0/abs(u)); + ENSURE (abs (rational_cast(src) - rational_cast(res)) <= 1.0/abs(u)); return res; } } // namespace util diff --git a/tests/library/rational-test.cpp b/tests/library/rational-test.cpp index bc0fc5a65..fe8f8e127 100644 --- a/tests/library/rational-test.cpp +++ b/tests/library/rational-test.cpp @@ -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_>() <::max()}; + const Rat MAXI = Rat{MAX}; + Rat poison = (MAXI-88)/(MAXI/7); + + auto approx = [](Rat rat){ return rational_cast (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); } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 45f917085..a70724fed 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -39874,9 +39874,9 @@ - + - + @@ -39887,17 +39887,20 @@

+
- + - + - + + + @@ -39940,6 +39943,7 @@ + @@ -40003,23 +40007,69 @@ - - + + + + + + + + + + +

+ damit kann ich stets so genau wie möglich rechnen +

+ +
+ +
+ + + + + + +
- - + + + + + + + + +

+ Rat poison = (MAXI-88)/(MAXI/7); +

+

+ ...das ist näherungsweise Sieben... +

+ +
+ +
+ + + + +
- + + + +