diff --git a/src/lib/random.hpp b/src/lib/random.hpp index 11046f1fa..bbad87741 100644 --- a/src/lib/random.hpp +++ b/src/lib/random.hpp @@ -38,6 +38,7 @@ #include "lib/integral.hpp" +#include "lib/hash-value.h" #include "lib/nocopy.hpp" #include @@ -79,6 +80,11 @@ namespace lib { uint64_t u64() { return uniformU_(generator_); } double uni() { return uniformD_(generator_); } + friend int rani(uint); + friend double ranRange(double,double); + friend double ranNormal(double,double); + friend HashVal ranHash(); + /** inject controlled randomisation */ void reseed (SeedNucleus&); @@ -119,7 +125,42 @@ namespace lib { /* ===== convenience accessors ===== */ - inline int rani() { return defaultGen.i32(); } ///< using default params: min ≡ 0, max ≡ numeric_limits + /** @return a random integer ∈ [0 ... bound[ */ + inline int + rani (uint bound =1u<<31) + { + if (!bound) ++bound; + --bound; + uint upper{std::numeric_limits::max()}; + upper = bound < upper? bound : upper; + std::uniform_int_distribution dist(0, upper); + return dist (defaultGen.generator_); + } + + /** @return a random double ∈ [start ... bound[ */ + inline double + ranRange (double start, double bound) + { + std::uniform_real_distribution dist{start,bound}; + return dist (defaultGen.generator_); + } + + inline double + ranNormal (double mean =0.0, double stdev =1.0) + { + std::normal_distribution dist{mean,stdev}; + return dist (defaultGen.generator_); + } + + /** @return a random *non-zero* HashVal */ + inline lib::HashVal + ranHash() + { + static std::uniform_int_distribution dist{lib::HashVal(1)}; + return dist (defaultGen.generator_); + } + + /// @deprecated inline uint64_t ranu() { return defaultGen.u64(); } inline double runi() { return defaultGen.uni(); } diff --git a/tests/library/random-test.cpp b/tests/library/random-test.cpp index ae18a18ad..f8c76e158 100644 --- a/tests/library/random-test.cpp +++ b/tests/library/random-test.cpp @@ -28,7 +28,10 @@ #include "lib/test/run.hpp" #include "lib/random.hpp" +#include "lib/util.hpp" +#include "lib/test/diagnostic-output.hpp" +using util::isLimited; namespace lib { namespace test { @@ -45,6 +48,7 @@ namespace test { run (Arg) { simpleUsage(); + verify_distributionVariants(); verify_reproducibleSequence(); } @@ -62,10 +66,44 @@ namespace test { int r2 = rani(); CHECK (0 <= r2 and r2 < RAND_MAX); - CHECK (r1 != r2); + CHECK (r1 != r2); // may fail with very low probability } + /** @test properties of predefined distributions provided for convenience + * - the upper bound for `rani(bound)` is exclusive + * - uniform distributions are sufficiently uniform + * - spread of normal distribution is within expected scale + */ + void + verify_distributionVariants() + { + double avg{0.0}; + const uint N = 1e6; + for (uint i=0; i < N; ++i) + avg += 1.0/N * rani (1000); + + auto expect = 500; + auto error = fabs(avg/expect - 1); + CHECK (error < 0.005); + + for (uint i=0; i < N; ++i) + CHECK (isLimited(0, rani(5), 4)); + + for (uint i=0; i < N; ++i) + CHECK (0 != ranHash()); + + auto sqr = [](double v){ return v*v; }; + + double spread{0.0}; + for (uint i=0; i < N; ++i) + spread += sqr (ranNormal() - 0.5); + spread = sqrt (spread/N); + CHECK (spread < 1.12); + } + + + /** @test demonstrate that random number sequences can be reproduced * - use a rigged SeedNucleus, always returning a fixed sees * - build two distinct random sequence generators, yet seeded diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index c7464d4c3..6f8e5cdf8 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -15226,9 +15226,7 @@ - - - +

nur einen Satz Klauseln @@ -16653,9 +16651,7 @@ - - - +

Grundlagen für InteractionControl @@ -17123,9 +17119,7 @@ - - - +

wie bestimmt? @@ -17738,9 +17732,7 @@ - - - +

das heißt: weitgehend custom drawing @@ -47254,9 +47246,7 @@ - - - +

dies setzt volle Implementierung @@ -47669,9 +47659,7 @@ - - - +

of questionable use @@ -47818,9 +47806,7 @@ - - - +

move into target @@ -57260,7 +57246,8 @@ - + + @@ -57291,13 +57278,14 @@ - - + + - + + @@ -57314,14 +57302,15 @@ - - + + - - + + - + + @@ -57427,6 +57416,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Die klasse enthält diverse Checks, die aber (weitgehend?) constexpr sind. Der eigentliche operative Aufruf ist eine reine Funktion, die den Generator hereingereicht bekommt. Diese Funktion gibt es in zwei Ausprägungen, einmal für einen einzigen Wert, und einmal (wohl optimiert) für Ausgabe in einen Iterator-Range. Letztere heißt __generate und ist wohl nur für die STL intern gedacht +

+ +
+
+ + + + + + + + + + +

+ an einigen wenigen Stellen wird eigens dafür gesorgt, daß die grenz inclusiv ist +

+ + +
+
+
+
+ + + + + + + + + +

+ rani(max) +

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +