From bdb2f12b8049853ce75ebb7683be9c060f651dfb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 21 Nov 2023 19:50:22 +0100 Subject: [PATCH] Library: RandomDraw - use dynamic quantiser For sake of simplicity, since this whole exercise is a byproduct, the mapping calculations are done in doubles. To get even distribution of values and a good randomisation, it is thus necessary to break down the size_t hash value in a first step (size_t can be 64bit and random numbers would be subject to rounding errors otherwise) The choice of this quantiser is tricky; it must be a power of two to guarantee even distribution, and if chosen to close to the grid of the result values, with lower probabilities we'd fail to cover some of the possible result values. If chosen to large, then of course we'd run danger of producing correlated numbers on consecutive picks. Attempting to use 4 bits of headroom above the log-2 of the required value range. For example, 10-step values would use a quantiser of 128, which looks like a good compromise. The following tests will show how good this choice holds up. --- src/lib/random-draw.hpp | 12 ++--- tests/library/random-draw-test.cpp | 31 +++++++++++- wiki/thinkPad.ichthyo.mm | 78 ++++++++++++++++++++++++------ 3 files changed, 97 insertions(+), 24 deletions(-) diff --git a/src/lib/random-draw.hpp b/src/lib/random-draw.hpp index 108ab4b6e..da54bfc2f 100644 --- a/src/lib/random-draw.hpp +++ b/src/lib/random-draw.hpp @@ -189,23 +189,23 @@ namespace lib { val *= maxResult_ - org; // [0 .. m[ val += org+1; // [1 .. m] val += CAP_EPSILON; // round down yet absorb dust - return Tar{val}; + return Tar{floor (val)}; } else// Origin is somewhere within value range {// ==> wrap "negative" part above max // to map 0.0 ⟼ org (≙neutral) val *= maxResult_ - minResult_; val += org+1; // max inclusive but <0 ⟼ org - if (val > maxResult_) // wrap the "negatives" + if (val >= maxResult_+1) // wrap the "negatives" val -= maxResult_+1 - minResult_; val += CAP_EPSILON; - return Tar{val}; + return Tar{floor (val)}; } - } - - static size_t constexpr QUANTISER = 1 << 8; + } //----headroom to accommodate low probabilities + static size_t constexpr QUANTISER = 1 << 4 + util::ilog2 (Tar::maxVal()-Tar::minVal()); static double constexpr CAP_EPSILON = 1/(2.0 * QUANTISER); + /** @internal draw from source of randomness */ double asRand (size_t hash) diff --git a/tests/library/random-draw-test.cpp b/tests/library/random-draw-test.cpp index 86886e5e2..495981130 100644 --- a/tests/library/random-draw-test.cpp +++ b/tests/library/random-draw-test.cpp @@ -55,7 +55,7 @@ namespace test{ // const Literal THE_END = "all dead and hero got the girl"; struct SymmetricFive - : function(size_t)> + : function(size_t)> { static size_t defaultSrc (size_t hash) { return hash; } @@ -136,9 +136,36 @@ namespace test{ { auto draw = Draw().probability(0.5); SHOW_EXPR (int(draw(0) )); +SHOW_EXPR (int(draw(63 ))); +SHOW_EXPR (int(draw(64 ))); +SHOW_EXPR (int(draw(70 ))); +SHOW_EXPR (int(draw(72 ))); +SHOW_EXPR (int(draw(82 ))); +SHOW_EXPR (int(draw(83 ))); +SHOW_EXPR (int(draw(84 ))); +SHOW_EXPR (int(draw(85 ))); +SHOW_EXPR (int(draw(86 ))); +SHOW_EXPR (int(draw(87 ))); +SHOW_EXPR (int(draw(88 ))); +SHOW_EXPR (int(draw(89 ))); +SHOW_EXPR (int(draw(90 ))); +SHOW_EXPR (int(draw(91 ))); +SHOW_EXPR (int(draw(92 ))); +SHOW_EXPR (int(draw(93 ))); +SHOW_EXPR (int(draw(94 ))); +SHOW_EXPR (int(draw(95 ))); +SHOW_EXPR (int(draw(96 ))); +SHOW_EXPR (int(draw(97 ))); +SHOW_EXPR (int(draw(102))); +SHOW_EXPR (int(draw(103))); +SHOW_EXPR (int(draw(108))); +SHOW_EXPR (int(draw(109))); +SHOW_EXPR (int(draw(121))); +SHOW_EXPR (int(draw(122))); SHOW_EXPR (int(draw(127))); SHOW_EXPR (int(draw(128))); -SHOW_EXPR (int(draw(141))); +SHOW_EXPR (int(draw(129))); +SHOW_EXPR (int(draw(192))); SHOW_EXPR (int(draw(255))); SHOW_EXPR (int(draw(256))); // CHECK (draw(0) == 0); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 49cd052e2..14a33b847 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -96728,14 +96728,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - + + + - + @@ -96749,18 +96749,46 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - + + + - + + + + + + + + + + +

+ natürliche Rundung is towards zero +

+ + +
+ + + + + +

+ ...und das ist obendrein implementation defined... +

+ + +
- - + +
+ + @@ -96770,12 +96798,20 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + + - + + - + + + + + + @@ -96794,6 +96830,16 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + +
+ + @@ -96811,8 +96857,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + +