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_>() <
#include
@@ -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 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 :"<::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...
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+