Library: now using controlled seed and replaced rand (closes #1378)

After augmenting our `lib/random.hpp` abstraction framework to add the necessary flexibility,
a common seeding scheme was ''built into the Test-Runner.''
 * all tests relying on some kind of randomness should invoke `seedRand()`
 * this draws a seed from the `entropyGen` — which is also documented in the log
 * individual tests can now be launched with `--seed` to force a dedicated seed
 * moreover, tests should build a coherent structure of linked generators,
   especially when running concurrently. The existing tests were adapted accordingly

All usages of `rand()` in the code base were investigated and replaced
by suitable calls to our abstraction framework; the code base is thus
isolated from the actual implementation, simplifying further adaptation.
This commit is contained in:
Fischlurch 2024-11-17 19:45:41 +01:00
parent 693ba32c8e
commit a20e233ca0
19 changed files with 508 additions and 207 deletions

View file

@ -45,6 +45,13 @@
namespace lib {
namespace {
inline uint constexpr
_iBOUND()
{
return 1u+uint(std::numeric_limits<int>::max());
}
}
/** Establishes a seed point for any instance or performance. */
class SeedNucleus
@ -64,26 +71,31 @@ namespace lib {
*/
template<class GEN>
class RandomSequencer
: util::NonCopyable
{
std::uniform_int_distribution<int> uniformI_;
std::uniform_int_distribution<uint64_t> uniformU_;
std::uniform_real_distribution<double> uniformD_;
GEN generator_;
public:
/** Random instances are created as part of an execution scheme */
RandomSequencer(SeedNucleus&);
/** Build new generator, drawing seed from a virtual seed source */
RandomSequencer (SeedNucleus&);
int i32() { return uniformI_(generator_); }
uint64_t u64() { return uniformU_(generator_); }
double uni() { return uniformD_(generator_); }
/** Build new generator, drawing a seed from given parent generator */
template<class G>
RandomSequencer (RandomSequencer<G>&);
friend int rani(uint);
friend double ranRange(double,double);
friend double ranNormal(double,double);
friend HashVal ranHash();
// default copy operations (can copy and assign a state)
int i(uint bound =_iBOUND()); ///< drop-in replacement for `rand() % bound`
int i32(); ///< random number from _full integer range_ (incl. negative values)
uint64_t u64(); ///< random 64bit number from full range.
double uni(); ///< random double drawn from interval `[0.0 ... 1.0[`
double range (double start, double bound); ///< random double from designated interval (upper bound excluded)
double normal(double mean=0.0, double stdev=1.0); ///< normal distribution (gaussian)
HashVal hash(); ///< _non-zero_ hash value from full 64bit range
/** generic adapter: draw next number to use the given distribution */
template<class DIST>
auto distribute(DIST);
/** inject controlled randomisation */
void reseed (SeedNucleus&);
@ -110,8 +122,9 @@ namespace lib {
};
/**
* PRNG engine to use by default: 64bit mersenne twister.
* PRNG engine to use by default: 64bit Mersenne twister.
*/
using Random = RandomSequencer<std::mt19937_64>;
@ -123,42 +136,35 @@ namespace lib {
extern Random entropyGen;
/* ===== convenience accessors ===== */
/** @return a random integer ∈ [0 ... bound[ */
inline int
rani (uint bound =1u<<31)
{
if (!bound) ++bound;
--bound;
uint upper{std::numeric_limits<int>::max()};
upper = bound < upper? bound : upper;
std::uniform_int_distribution<int> dist(0, upper);
return dist (defaultGen.generator_);
}
rani (uint bound =_iBOUND())
{
return defaultGen.i(bound);
}
/** @return a random double ∈ [start ... bound[ */
inline double
ranRange (double start, double bound)
{
std::uniform_real_distribution<double> dist{start,bound};
return dist (defaultGen.generator_);
}
{
return defaultGen.range (start, bound);
}
inline double
ranNormal (double mean =0.0, double stdev =1.0)
{
std::normal_distribution<double> dist{mean,stdev};
return dist (defaultGen.generator_);
}
ranNormal(double mean =0.0, double stdev =1.0)
{
return defaultGen.normal (mean, stdev);
}
/** @return a random *non-zero* HashVal */
inline lib::HashVal
ranHash()
{
static std::uniform_int_distribution<lib::HashVal> dist{lib::HashVal(1)};
return dist (defaultGen.generator_);
}
{
return defaultGen.hash();
}
/** inject true randomness into the #defaultGen */
@ -169,15 +175,20 @@ namespace lib {
/* ===== Implementation details ===== */
template<class GEN>
inline
RandomSequencer<GEN>::RandomSequencer (SeedNucleus& nucleus)
: uniformI_{0}
, uniformU_{0}
, uniformD_{}
, generator_{nucleus.getSeed()}
: generator_{nucleus.getSeed()}
{ }
template<class GEN>
template<class G>
inline
RandomSequencer<GEN>::RandomSequencer (RandomSequencer<G>& parent)
: generator_{RandomSequencer<GEN>::Seed{parent}.getSeed()}
{ }
@ -189,5 +200,115 @@ namespace lib {
}
template<class GEN>
template<class DIST>
inline auto
RandomSequencer<GEN>::distribute (DIST distribution)
{
return distribution (generator_);
}
/** @param bound upper bound (exclusive!) */
template<class GEN>
inline int
RandomSequencer<GEN>::i (uint bound)
{
if (!bound) bound=1;
--bound;
uint upper{std::numeric_limits<int>::max()};
upper = bound < upper? bound : upper;
return distribute (std::uniform_int_distribution<int> (0, upper));
}
template<class GEN>
inline int
RandomSequencer<GEN>::i32()
{
return distribute (std::uniform_int_distribution<int> {std::numeric_limits<int>::min()
,std::numeric_limits<int>::max()});
}
template<class GEN>
inline uint64_t
RandomSequencer<GEN>::u64()
{
return distribute (std::uniform_int_distribution<uint64_t> {std::numeric_limits<uint64_t>::min()
,std::numeric_limits<uint64_t>::max()});
}
template<class GEN>
inline double
RandomSequencer<GEN>::uni()
{
return range (0.0, 1.0);
}
template<class GEN>
inline double
RandomSequencer<GEN>::range (double start, double bound)
{
return distribute (std::uniform_real_distribution<double>{start,bound});
}
template<class GEN>
inline double
RandomSequencer<GEN>::normal (double mean, double stdev)
{
return distribute (std::normal_distribution<double>{mean,stdev});
}
template<class GEN>
inline HashVal
RandomSequencer<GEN>::hash()
{
return distribute (std::uniform_int_distribution<lib::HashVal>{lib::HashVal(1)});
}
/**
* Adapter to protect against data corruption caused by concurrent access.
* Random number generators in general are _not thread safe;_ when used from
* several threads concurrently, it is not a question _if_, but only a question
* _when_ the internal state will become corrupted, leading to degraded and biased
* distributions of produced numbers. For some usage scenarios however, ignoring
* this fact and still using a single generator from several threads may be acceptable,
* if the quality of the distribution actually does not matter and only some diffusion
* of numbers is required (e.g. adding a random sleep interval). But there is a catch:
* whenever the value range of generated numbers is less than the total range of the used
* data representation, then corruption of the internal state may lead to producing numbers
* outside the defined range. This adapter can be used to safeguard against this scenario.
* @remark typically using a 64bit generator on a 64bit platform is inherently safe, yet
* using a 32bit generator may rely on 64bit values internally, and then this problem
* may be triggered. See RandomConcurrent_test with the 32bit Mersenne twister as demo.
*/
template<class GEN>
class CappedGen
: public GEN
{
public:
using GEN::GEN;
typename GEN::result_type
operator()()
{
if constexpr (GEN::max() < std::numeric_limits<typename GEN::result_type>::max())
return GEN::operator()() % (GEN::max()+1);
else
return GEN::operator()();
}
};
template<class GEN>
auto
buildCappedSubSequence (RandomSequencer<GEN>& src)
{
typename RandomSequencer<GEN>::Seed seedChain(src);
RandomSequencer<CappedGen<GEN>> subSeq{seedChain};
return subSeq;
}
} // namespace lib
#endif /*LIB_RANDOM_H*/

View file

@ -83,7 +83,7 @@ namespace microbenchmark {
wrap (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t)
(size_t) mutable
{
functor();
return size_t(1);
@ -101,7 +101,7 @@ namespace microbenchmark {
wrap (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t i)
(size_t i) mutable
{
return size_t(functor(i));
};
@ -117,7 +117,7 @@ namespace microbenchmark {
wrap (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t)
(size_t) mutable
{
return size_t(functor());
};
@ -133,7 +133,7 @@ namespace microbenchmark {
wrap (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t i)
(size_t i) mutable
{
functor(i);
return size_t(1);

View file

@ -165,9 +165,10 @@ namespace test{
struct Thread
: lib::ThreadJoinable<>
{
Thread(Subject const& testSubject, size_t loopCnt, SyncBarrier& testStart)
Thread(Subject const& subject, size_t loopCnt, SyncBarrier& testStart)
: ThreadJoinable{"Micro-Benchmark"
,[=, &testStart]() // local copy of the test-subject-Functor
,[this,loopCnt, testSubject=subject, &testStart]
() mutable // local (mutable) copy of the test-subject-Functor
{
testStart.sync(); // block until all threads are ready
auto start = steady_clock::now();

View file

@ -17,6 +17,6 @@ return: 0
END
TEST "Concurrent PRNG access" RandomConcurrent_test << END
TEST "Concurrent PRNG access" RandomConcurrent_test quick << END
return: 0
END

View file

@ -187,6 +187,7 @@ namespace test{
uint64_t consumerSum = 0;
SyncBarrier& trigger_;
Random rand_;
void
countConsumerCall (uint increment)
@ -198,13 +199,13 @@ namespace test{
Worker(CallQueue& queue, SyncBarrier& commonTrigger)
: ThreadJoinable{"CallQueue_test: concurrent dispatch"
, [&]() {
uint cnt = rand() % MAX_RAND_STEPS; //////////////////////////////OOO brauche rani auf lokalem Generator!
uint delay = rand() % MAX_RAND_DELAY;
uint cnt = rand_.i(MAX_RAND_STEPS);
uint delay = rand_.i(MAX_RAND_DELAY);
trigger_.sync(); // block until all threads are ready
for (uint i=0; i<cnt; ++i)
{
uint increment = rand() % MAX_RAND_INCMT;
uint increment = rand_.i(MAX_RAND_INCMT);
queue.feed ([=]() { countConsumerCall(increment); });
producerSum += increment;
usleep (delay);
@ -212,6 +213,7 @@ namespace test{
} // and thus belonging to some random other thread
}}
, trigger_{commonTrigger}
, rand_{defaultGen}
{ }
};
@ -227,7 +229,7 @@ namespace test{
void
verify_ThreadSafety()
{
////////////////////////////////////////////////OOO seedRandom()
seedRand();
CallQueue queue;
SyncBarrier trigger{NUM_OF_THREADS + 1};

View file

@ -57,7 +57,7 @@ namespace test{
Sub()
: TestTargetObj(created++)
,instanceID_(rand() % MAX_ID)
,instanceID_(rani(MAX_ID))
{ }
virtual operator string() const

View file

@ -162,6 +162,7 @@ namespace test{
void
verify_heavilyParallelUsage()
{
seedRand();
auto verifyResult = [](VecI sequence)
{
uint prev = 0;
@ -183,28 +184,21 @@ namespace test{
}
/** build a call stack within separate thread and capture diagnostics */
/**
* Build a call stack within separate thread and capture diagnostics.
* The actual test operation produces a descending number sequence,
* and only odd values will be captured into the diagnostic stack-
*/
struct TestThread
: ThreadJoinable<VecI>
{
TestThread()
: ThreadJoinable("test context stack"
,&verifyDiagnosticStack)
: ThreadJoinable{"test context stack"
,[seed = 1+rani(MAX_RAND)]
{ return descend (seed); }}
{ }
};
/** the actual test operation running in a separate thread
* produces a descending number sequence, and only odd values
* will be captured into the diagnostic stack
*/
static VecI
verifyDiagnosticStack()
{
uint seed (1 + rand() % MAX_RAND); /////////////////////////OOO brauche rani() auf lokalem Generator
return descend (seed);
}
static VecI
descend (uint current)
{
@ -213,7 +207,7 @@ namespace test{
sleep_for (500us);
if (isOdd(current))
if (isOdd (current))
{
Marker remember(current);
return descend (current+1);

View file

@ -47,6 +47,7 @@
#include "lib/random.hpp"
#include "lib/util.hpp"
#include <cstdlib>
#include <utility>
#include <array>
@ -183,9 +184,11 @@ namespace test{
TypedCounter testCounter;
auto testSubject = [&, i = rani(MAX_INDEX)]
(size_t) -> size_t
auto testSubject = [&
,gen = makeRandGen()]
(size_t) mutable -> size_t
{
uint i = gen.i(MAX_INDEX);
operators[i](testCounter);
return 1;
};

View file

@ -58,7 +58,7 @@
** Astute readers might have noticed, that the test fixture is sloppy with respect to proper
** locking and synchronisation. Rather, some explicit sleep commands are interspersed in a way
** tuned to work satisfactory in practice. This whole approach can only work, because each
** Posix locking call actually requires the runtime system to issue a read/write barrier,
** POSIX locking call actually requires the runtime system to issue a read/write barrier,
** which are known to have global effects on the relevant platforms (x86 and x86_64).
** And because the production relevant code in SteamDispatcher uses sufficient (in fact
** even excessive) locking, the state variables of the test fixture are properly synced
@ -322,11 +322,12 @@ namespace test {
* sequential calculation and summation
*/
void
perform_massivelyParallel(Arg args_for_stresstest)
perform_massivelyParallel (Arg args_for_stresstest)
{
maybeOverride(NUM_THREADS_DEFAULT, args_for_stresstest, 1);
maybeOverride(NUM_INVOC_PER_THRED, args_for_stresstest, 2);
maybeOverride(MAX_RAND_DELAY_us, args_for_stresstest, 3);
seedRand();
maybeOverride (NUM_THREADS_DEFAULT, args_for_stresstest, 1);
maybeOverride (NUM_INVOC_PER_THRED, args_for_stresstest, 2);
maybeOverride (MAX_RAND_DELAY_us, args_for_stresstest, 3);
// we'll run several instances of the following thread....
@ -336,11 +337,12 @@ namespace test {
SyncBarrier& barrier_;
FamilyMember<InvocationProducer> id_;
vector<string> cmdIDs_;
lib::Random random_;
lib::ThreadJoinable<void> thread_;
Symbol
cmdID(uint j)
cmdID (uint j)
{
cmdIDs_.push_back (_Fmt("%s.thread-%02d.%d") % COMMAND_ID % id_ % j);
return cStr(cmdIDs_.back());
@ -350,6 +352,7 @@ namespace test {
public:
InvocationProducer (SyncBarrier& trigger)
: barrier_{trigger}
, random_{defaultGen}
, thread_{"producer", [&]{ fabricateCommands(); }}
{ }
@ -376,16 +379,16 @@ namespace test {
}
static void
sendCommandMessage(GenNode msg)
sendCommandMessage (GenNode msg)
{
SessionCommand::facade().trigger (msg.idi.getSym(), msg.data.get<Rec>());
}
static void
void
__randomDelay()
{
if (not MAX_RAND_DELAY_us) return;
sleep_for (microseconds (1 + rand() % MAX_RAND_DELAY_us)); // random delay varying in steps of 1µs
sleep_for (microseconds (1 + random_.i(MAX_RAND_DELAY_us))); // random delay varying in steps of 1µs
}
};

View file

@ -230,7 +230,7 @@ namespace test{
public:
Special()
: Probe<555>()
, secret_('a' + (rand() % (1+'z'-'a')))
, secret_('a' + rani('z'-'a' +1))
{
checksum += secret_;
}

View file

@ -222,8 +222,11 @@ namespace test{
watch.expectThreads(CONCURR)
.expectIncidents(10000);
auto act = [&]{ // two nested activities with random delay
uint delay = 100 + rand() % 800;
auto act = [&
,gen = makeRandGen()]// local random generator per thread
() mutable
{ // two nested activities with random delay
uint delay = 100 + gen.i(800);
watch.markEnter();
sleep_for (microseconds(delay));
watch.markEnter(2);

View file

@ -40,9 +40,6 @@
#include <deque>
#include <tuple>
//#include <array>
//using util::isLimited;
//using std::array;
using std::tuple;
using std::deque;
using util::_Fmt;
@ -66,13 +63,62 @@ namespace test {
{
virtual void
run (Arg)
run (Arg arg)
{
seedRand();
investigate_concurrentAccess();
benchmark_random_gen();
if ("quick" != firstTok (arg))
investigate_concurrentAccess();
}
/** @test microbenchmark of various random number generators
* @remark typical values
* - `rand()` (trinomial generator) : 15ns / 10ns (O3)
* - Mersenne twister 64bit : 55ns / 25ns (O3)
* - reading /dev/urandom : 480ns / 470 (O3)
*/
void
benchmark_random_gen()
{
auto do_nothing = []{ /* take it easy */ };
auto mersenne64 = []{ return rani(); };
auto legacy_gen = []{ return rand(); };
std::random_device entropySource{"/dev/urandom"};
auto rly_random = [&]{ return entropySource(); };
_Fmt resultDisplay{"µ-bench(%s)%|45T.| %5.3f µs"};
double d1 = microBenchmark (do_nothing, NUM_INVOKES).first;
cout << resultDisplay % "(empty call)" % d1 <<endl;
double d2 = microBenchmark (mersenne64, NUM_INVOKES).first;
cout << resultDisplay % "Mersenne-64" % d2 <<endl;
double d3 = microBenchmark (legacy_gen, NUM_INVOKES).first;
cout << resultDisplay % "std::rand()" % d3 <<endl;
double d4 = microBenchmark (rly_random, NUM_INVOKES).first;
cout << resultDisplay % "/dev/urandom" % d4 <<endl;
CHECK (d3 < d2 and d2 < d4);
}
/**
* Research setup to investigate concurrent access to a random generator.
* From each test thread, the shared generator instance is invoked a huge number times
* (defined by NUM_INVOKES), thereby computing the mean value and checking for defect
* numbers outside the generator's definition range. This probe cycle is repeated
* several times (defined by NUM_SAMPLES) and the results are collected and evaluated
* afterwards to detect signs of a skewed distribution.
* @tparam GEN a C++ compliant generator type
* @tparam threads number of threads to run in parallel
* @remark Pseudo random number generation as such is not threadsafe, and pressing for
* concurrent access (as done here) will produce a corrupted internal generator
* state sooner or later. Under some circumstances however, theses glitches
* can be ignored, if quality of generated numbers actually does not matter.
*/
template<typename GEN, uint threads>
struct Experiment
: Sync<>
@ -103,7 +149,7 @@ namespace test {
double percentTilted {0.0};
bool isFailure {false};
/** run the experiment series */
void
perform()
{
@ -116,7 +162,7 @@ namespace test {
auto r = generator();
if (r < GEN::min() or r > GEN::max())
++fail;
avg += 1.0/N * r;//(r % Engine::max());
avg += 1.0/N * r;
}
auto error = avg/expect - 1;
recordRun (error, fail);
@ -128,7 +174,7 @@ namespace test {
_Fmt resultLine{"%6.3f ‰ : %d %s"};
for (auto [err,fails] : results)
{
bool isGlitch = fails or fabs(err) >0.003;
bool isGlitch = fails or fabs(err) > 3 * 1/sqrt(N); // mean of a sound distribution will remain within bounds
cout << resultLine % (err*1000)
% fails
% (fails? "FAIL": isGlitch? " !! ":"") << endl;
@ -138,8 +184,8 @@ namespace test {
}
// assess overall results......
percentGlitches = 100.0 * glitches/cases;
percentTilted = 100.0 * fabs(double(lows)/cases - 0.5)*2;
isFailure = glitches or percentTilted > 30;
percentTilted = 100.0 * fabs(double(lows)/cases - 0.5)*2; // degree to which mean is biased for one side
isFailure = glitches or percentTilted > 30; // (empirical trigger criterion)
cout << _Fmt{"++-------------++ %s\n"
" Glitches: %5.1f %%\n"
" Tilted: %5.1f %%\n"
@ -152,24 +198,33 @@ namespace test {
};
/** @test examine behaviour of PRNG under concurrency stress */
/** @test examine behaviour of PRNG under concurrency stress
* - running a 32bit generator single threaded should not trigger alarms
* - while under concurrent pressure several defect numbers should be produced
* - even the 64bit generator will show uneven distribution due to corrupted state
* - the 32bit generator capped to its valid range exhibits skew only occasionally
* @see lib::CappedGen
*/
void
investigate_concurrentAccess()
{
using Mersenne32 = std::mt19937;
using Mersenne64 = std::mt19937_64;
using Mersenne32 = std::mt19937;
using CappedMs32 = CappedGen<Mersenne32>;
Experiment<Mersenne32,1> single32{Mersenne32(defaultGen.uni())};
Experiment<Mersenne32,NUM_THREADS> concurr32{Mersenne32(defaultGen.uni())};
Experiment<Mersenne64,NUM_THREADS> concurr64{Mersenne64(defaultGen.uni())};
Experiment<Mersenne32,1> single_mers32{Mersenne32(defaultGen.uni())};
Experiment<Mersenne32,NUM_THREADS> concurr_mers32{Mersenne32(defaultGen.uni())};
Experiment<Mersenne64,NUM_THREADS> concurr_mers64{Mersenne64(defaultGen.uni())};
Experiment<CappedMs32,NUM_THREADS> concCap_mers32{CappedMs32(defaultGen.uni())};
single32.perform();
concurr32.perform();
concurr64.perform();
single_mers32.perform();
concurr_mers32.perform();
concurr_mers64.perform();
concCap_mers32.perform();
CHECK (not single32.isFailure, "ALARM : single-threaded Mersenne-Twister 32bit produces skewed distribution");
CHECK ( single32.isFailure, "SURPRISE : Mersenne-Twister 32bit encountered NO glitches under concurrent pressure");
CHECK ( single64.isFailure, "SURPRISE : Mersenne-Twister 64bit encountered NO glitches under concurrent pressure");
CHECK (not single_mers32.isFailure, "ALARM : single-threaded Mersenne-Twister 32bit produces skewed distribution");
CHECK ( concurr_mers32.isFailure, "SURPRISE : Mersenne-Twister 32bit encountered NO glitches under concurrent pressure");
CHECK ( concurr_mers64.isFailure, "SURPRISE : Mersenne-Twister 64bit encountered NO glitches under concurrent pressure");
}
};

View file

@ -69,15 +69,16 @@ namespace test {
public:
TestThread()
: Thread{"Load Test"
,[&]()
,[&, ran=lib::Random{seedFromDefaultGen()}]
() mutable
{ //-STAGE-1------------------------------
localSum = rand() % 1000; // generate local value
localSum = ran.i(1000); // generate local value
stage1.fetch_add (localSum); // book in local value
interThread.sync(); // wait for all other threads to have booked in
//-STAGE-2------------------------------
uint sync = stage1; // pick up compounded sum from STAGE-1
localSum += rand() % 1000; // add further local value for STAGE-2
localSum += ran.i(1000); // add further local value for STAGE-2
stage2.fetch_add (localSum+sync); // book in both local values and synced sum
afterThread.sync(); // wait for other threads and supervisor
@ -117,6 +118,8 @@ namespace test {
virtual void
run (Arg)
{
seedRand();
// Launch several TestThread
array<TestThread,NUM_THREADS> threads;
CHECK (0 == finish);

View file

@ -63,6 +63,8 @@ namespace test {
virtual void
run (Arg)
{
seedRand();
auto gen = buildCappedSubSequence(defaultGen);
int contended = 0;
using Threads = lib::ScopedCollection<ThreadJoinable<>>;
@ -75,7 +77,7 @@ namespace test {
,[&]{
for (uint i=0; i<NUM_LOOP; ++i)
{
uint delay = rand() % 10;
uint delay = gen.i(10);
usleep (delay);
{
ClassLock<void> guard;
@ -87,7 +89,7 @@ namespace test {
};
for (auto& thread : threads)
thread.join(); // block until thread terminates
thread.join(); // block until thread terminates // @suppress("Return value not evaluated")
CHECK (contended == NUM_THREADS * NUM_LOOP,
"ALARM: Lock failed, concurrent modification "

View file

@ -138,6 +138,8 @@ namespace test {
virtual void
run (Arg)
{
seedRand();
attachNewBusTerm();
commandInvocation();
captureStateMark();
@ -669,17 +671,20 @@ namespace test {
: ThreadJoinable{"BusTerm_test: asynchronous diff mutation"
, [=]
{
uint cnt = rand() % MAX_RAND_BORGS;
uint cnt = randGen_.i(MAX_RAND_BORGS);
for (uint i=0; i<cnt; ++i)
{
uint delay = rand() % MAX_RAND_DELAY;
uint id = rand() % MAX_RAND_NUMBS;
uint delay = randGen_.i(MAX_RAND_DELAY);
uint id = randGen_.i(MAX_RAND_NUMBS);
usleep (delay);
scheduleBorg (id);
notifyGUI (new BorgGenerator{*this, i});
}
}}
{ }
private:
lib::Random randGen_{lib::seedFromDefaultGen()};
};

View file

@ -464,7 +464,7 @@ namespace test {
CHECK (3 == wof.size());
while (check < 6'000)
sleep_for(10ms); // .....sufficiently long to count way beyond 10'000
sleep_for(15ms); // .....sufficiently long to count way beyond 10'000
CHECK (check > 6'000);
CHECK (1 == wof.size());
}

View file

@ -133,7 +133,7 @@ namespace test {
Extent& extent{*it};
CHECK (10 == extent.size());
int num = rand() % 1000;
int num = rani(1000);
extent[2] = num;
CHECK (num == extent[2]);
@ -173,7 +173,7 @@ namespace test {
struct Probe
{
short val;
Probe() : val(1 + rand() % 1000) { }
Probe() : val(1 + rani(1000)) { }
~Probe() { val = 0; }
};

View file

@ -7178,10 +7178,10 @@ An Activity is //performed// by invoking its {{{activate(now, ctx)}}} function -
In a similar vein, also ''dependency notifications'' need to happen decoupled from the activity chain from which they originate; thus the Post-mechanism is also used for dispatching notifications. Yet notifications are to be treated specially, since they are directed towards a receiver, which in the standard case is a {{{GATE}}}-Activity and will respond by //decrementing its internal latch.// Consequently, notifications will be sent through the ''λ-post'' -- which operationally re-schedules a continuation as a follow-up job. Receiving such a notification may cause the Gate to become opened; in this case the trigger leads to //activation of the chain// hooked behind the Gate, which at some point typically enters into another calculation job. Otherwise, if the latch (in the Gate) is already zero (or the deadline has passed), nothing happens. Thus the implementation of state transition logic ensures the chain behind a Gate can only be //activated once.//
</pre>
</div>
<div title="RenderProcess" modifier="Ichthyostega" created="200706190705" modified="202410300145" tags="Rendering operational" changecount="12">
<pre>At a high level, the Render Process is what „runs“ a playback or render. Using the EngineFaçade, the [[Player]] creates a descriptor for such a process, which notably defines a [[»calculation stream«|CalcStream]] for each individual //data feed// to be produced. To actually implement such an //ongoing stream of timed calculations,// a series of data frames must be produced, for which some source data must be loaded and then individual calculations must be scheduled to work on this data and deliver results within a well defined time window for each frame. Thus, on the implementation level, a {{{CalcStream}}} comprises a pipeline to define [[render jobs|RenderJob]], and a self-repeating re-scheduling mechanism to repeatedly plan and dispatch a //chunk of render jobs// to the [[Scheduler]], which cares to invoke the individual jobs in due time.
<div title="RenderProcess" modifier="Ichthyostega" created="200706190705" modified="202411010046" tags="Rendering operational" changecount="20">
<pre>At a high level, the Render Process is what „runs“ a playback or render. Using the EngineFaçade, the [[Player]] creates a descriptor for such a process, which notably defines a [[»calculation stream«|CalcStream]] for each individual //data feed// to be produced. To actually implement such an //ongoing stream of timed calculations,// a series of data frames must be produced, for which some source data has to be loaded and then individual calculations will be scheduled to work on this data and deliver results within a well defined time window for each frame. Thus, on the implementation level, a {{{CalcStream}}} comprises a pipeline to define [[render jobs|RenderJob]], and a self-repeating re-scheduling mechanism to repeatedly plan and dispatch a //chunk of render jobs// to the [[Scheduler]], which cares to invoke the individual jobs in due time.
This leads to a even more detailed implementation level of the ''render processing''. Within the [[Session]], the user has defined the »edit« or the definition of the media product as an arrangement of media elements placed and arranged into a [[Timeline]]. A repeatedly-running, demand-driven, compiler-like process in Lumiera (known as [[the Builder|Builder]]) consolidates this [[»high-level definition«|HighLevelModel]] into a [[Fixture]] and an directly attached [[network of Render Nodes|LowLevelModel]]. The Fixture hereby defines a [[segment for each part of the timeline|Segmentation]], which can be represented by a single topology of connected render nodes. So each segment spans a time range, quantised into a range of frames -- and the node network attached below this segment is capable of producing media data for each frame within definition range, when given the actual frame number, and some designation of the actual data feed required at that point. Yet it depends on the circumstances what this »data feed« //actually is;// as a rule, anything which can be produced and consumed as compound will be represented as //a single feed.// The typical video will thus comprise a video feed and a stereo sound feed, while another setup may require to deliver individual sound feeds for the left and right channel, or whatever channel layout the sound system has, and it may require two distinct beamer feeds for the two channels of stereoscopic video. However -- as a general rule of architecture -- the Lumiera Render Engine is tasked to perform //all of the processing work,// up to and including all adaptation steps to reach the desired final result. Thus, for rendering into a media container, only a single feed is required, which can be drawn from an encoder node, which in turn consumes several data feeds for its constituents.
This leads to a even more detailed description at implementation level of the ''render processing''. Within the [[Session]], the user has defined the »edit« or the definition of the media product as a collection of media elements placed and arranged into a [[Timeline]]. A repeatedly-running, demand-driven, compiler-like process (in Lumiera known as [[the Builder|Builder]]) consolidates this [[»high-level definition«|HighLevelModel]] into a [[Fixture]] and a [[network of Render Nodes|LowLevelModel]] directly attached below. The Fixture hereby defines a [[segment for each part of the timeline|Segmentation]], which can be represented as a distinct and non-changing topology of connected render nodes. So each segment spans a time range, quantised into a range of frames -- and the node network attached below this segment is capable of producing media data for each frame within definition range, when given the actual frame number, and some designation of the actual data feed required at that point. Yet it depends on the circumstances what this »data feed« //actually is;// as a rule, anything which can be produced and consumed as compound will be represented as //a single feed.// The typical video will thus comprise a video feed and a stereo sound feed, while another setup may require to deliver individual sound feeds for the left and right channel, or whatever channel layout the sound system has, and it may require two distinct beamer feeds for the two channels of stereoscopic video. However -- as a general rule of architecture -- the Lumiera Render Engine is tasked to perform //all of the processing work,// up to and including any adaptation step required to reach the desired final result. Thus, for rendering into a media container, only a single feed is required, which can be drawn from an encoder node, which in turn consumes several data feeds for its constituents.
To summarise this break-down of the rendering process defined thus far, the [[Scheduler]] ''invokes'' individual [[frame render jobs|RenderJob]], each of which defines a set of »coordinates«:
* an ID of the calculation stream allowing to retrieve the output sink

View file

@ -17172,9 +17172,7 @@
</node>
<node CREATED="1563020429008" FOLDED="true" ID="ID_8715605" MODIFIED="1678461929265">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<b>UIStyle</b>: der &#187;<u><font color="#2f297a">StyleManager</font></u>&#171;
@ -17672,9 +17670,7 @@
<node CREATED="1625069192432" ID="ID_709423265" MODIFIED="1625069203664" TEXT="macht eigentlich exakt was wir brauchen"/>
<node CREATED="1625069204446" ID="ID_47523093" MODIFIED="1625069786876" TEXT="aber etwas &#xbb;fest verdrahtet&#xab;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -18528,9 +18524,7 @@
</node>
<node CREATED="1664028417616" ID="ID_743592439" MODIFIED="1664028542302" TEXT="idealerweise l&#xe4;&#xdf;t sich das jedoch &#xfc;ber den Parent-Container automatisieren">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...unter der Annahme, da&#223; letzlich eine &quot;invalidation&quot; des Widgets gen&#252;gt, lie&#223;e sich das elegant l&#246;sen, indem der Canvas-Container insgesamt &quot;invalidated&quot; wird.
@ -18938,9 +18932,7 @@
<font NAME="SansSerif" SIZE="10"/>
<node COLOR="#33565a" CREATED="1664725557464" ID="ID_1964737255" MODIFIED="1664727540443" TEXT="reduce(Name)? &#x27f9; &#x25a3;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
BEDINGUNG: &#916;Name &gt; goal
@ -19604,9 +19596,7 @@
</node>
<node CREATED="1665872631421" ID="ID_102284502" MODIFIED="1665872716207" TEXT="f&#xfc;r das lokale pop-up-Men&#xfc;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...welches u.U. zwar vom ElementBoxWidget aus eingebunden wird, aber eigentlich auf die Inhalts-Ebene delegiert
@ -20738,9 +20728,7 @@
<node CREATED="1480725000029" ID="ID_1586514211" MODIFIED="1518487921080" TEXT="wir steigen stets auf Ebene einer Timeline ein"/>
<node CREATED="1480725012731" ID="ID_9332776" MODIFIED="1576282358097">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<i>aber:</i>&#160;Binding im Diff-System durchaus m&#246;glich
@ -23084,9 +23072,7 @@
<node CREATED="1480776087027" ID="ID_132590373" MODIFIED="1518487921082" TEXT="leer zulassen">
<node CREATED="1480778115091" ID="ID_1948130012" MODIFIED="1576282358080" TEXT="das hei&#xdf;t...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
die betreffenden Felder sind echt optional.
@ -43042,9 +43028,7 @@
<icon BUILTIN="info"/>
<node CREATED="1670634343385" ID="ID_284249821" MODIFIED="1670634414906" TEXT="detox(changedMetric) macht nix">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
da die Metrik ja limitiert wurde und damit per definitionem auch sauber
@ -44373,9 +44357,7 @@
<node CREATED="1669994645898" ID="ID_448193400" MODIFIED="1669994655184" TEXT="f2 : der limitierende Gegen-Faktor"/>
<node CREATED="1669995461568" ID="ID_1761342962" MODIFIED="1669995622760" TEXT="ist ein Kehrwert">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
aus Gr&#252;nden der Symmetrie kann man das gleiche Argument jeweils auch auf den Kehrwert anwenden, deshalb haben wir ja 4 F&#228;lle (bei zwei Eingangs-Faktoren). Man mu&#223; nur ggfs. dann den Kehrwert vom Ergebnis ausgeben. Beispiel: wir nehmen den Z&#228;hler vom ersten Faktor als Quantisierer. Dann ist f1 der Nenner vom ersten Faktor, und mu&#223; daher auch im Ergebnis im Nenner landen, nicht im Z&#228;hler wie beim regul&#228;ren Schema
@ -46248,9 +46230,7 @@
<node CREATED="1523019593833" ID="ID_770462134" MODIFIED="1557498707235" TEXT="ausschlie&#xdf;lich an das UI-Toolkit gebunden"/>
<node CREATED="1523019635739" ID="ID_883974404" MODIFIED="1576282358018" TEXT="Einzelfall-Wissen vorausgesetzt">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
man mu&#223; die Implementierungs-Details <i>jeder einzelnen Komponente</i>&#160;kennen,
@ -46497,9 +46477,7 @@
</node>
<node CREATED="1448078731130" ID="ID_1682515267" MODIFIED="1576282358016" TEXT="collapse / expand">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
daf&#252;r gen&#252;gt der normale Reset
@ -46671,9 +46649,7 @@
</node>
<node CREATED="1541546692289" ID="ID_189279804" MODIFIED="1541546864673">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<b>Identit&#228;t</b>&#160;== Bus-ID
@ -46779,9 +46755,7 @@
<node CREATED="1535639174623" ID="ID_1755607605" MODIFIED="1535639177466" TEXT="Revealer">
<node CREATED="1535639368981" ID="ID_220149026" MODIFIED="1576282358011">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<i>nicht</i>&#160;bool-Testbar
@ -56486,7 +56460,7 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1710518610461" FOLDED="true" ID="ID_629444459" MODIFIED="1710518761306" TEXT="Zufallszahlen-Sequenzen">
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1710518610461" ID="ID_629444459" MODIFIED="1731845694904" TEXT="Zufallszahlen-Sequenzen">
<arrowlink COLOR="#ff0029" DESTINATION="ID_552644754" ENDARROW="Default" ENDINCLINATION="-438;679;" ID="Arrow_ID_440516587" STARTARROW="None" STARTINCLINATION="-377;-45;"/>
<icon BUILTIN="hourglass"/>
<icon BUILTIN="messagebox_warning"/>
@ -56504,6 +56478,109 @@
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1731845750385" ID="ID_810712062" MODIFIED="1731845774415" TEXT="Abstraktions-Framework">
<node CREATED="1731845775617" ID="ID_1139075257" MODIFIED="1731845790075" TEXT="Basis ist &lt;random&gt;"/>
<node CREATED="1731845922430" ID="ID_1112739568" MODIFIED="1731845927401" TEXT="Anforderungen">
<node CREATED="1731845928234" ID="ID_625386997" MODIFIED="1731845944583" TEXT="soll den eigentlichen Grenerator einh&#xfc;llen/verbergen"/>
<node CREATED="1731845951618" ID="ID_1530478572" MODIFIED="1731846319486" TEXT="Laufzeit-Virtualisierung f&#xfc;r die Seed-Quelle (&#xbb;SeedNucleus&#xab;)">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
es soll m&#246;glich seine, eine opaque Quelle zu &#252;bergeben und erst zur Laufzeit / dynamisch bestimmen, woher der Seed stammt; Entscheidung per late-binding, ob echte Entropie zum Einsatz kommt, oder eine reproduzierbare Sequenz oder gar ein fixierter Wert
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#8f8f94" DESTINATION="ID_597020246" ENDARROW="Default" ENDINCLINATION="112;0;" ID="Arrow_ID_138451619" STARTARROW="None" STARTINCLINATION="107;5;"/>
</node>
<node CREATED="1731846140248" ID="ID_1929928174" MODIFIED="1731846150229" TEXT="Generator-Zustand als Instanz dargestellt"/>
<node CREATED="1731846151719" ID="ID_383905336" MODIFIED="1731846161905" TEXT="es soll einen impliziten default-Generator geben"/>
<node CREATED="1731846177732" ID="ID_1575311077" MODIFIED="1731846190342" TEXT="Generatoren sollen als Baukasten-System zusammenpassen">
<node CREATED="1731846205624" ID="ID_450085518" MODIFIED="1731846212709" TEXT="der default-Generator ist nicht speziell"/>
<node CREATED="1731846213343" ID="ID_1947266937" MODIFIED="1731846219986" TEXT="sondern eine convenience-Abk&#xfc;rzung"/>
</node>
</node>
<node CREATED="1731846233220" ID="ID_1589656875" MODIFIED="1731859613091" TEXT="Struktur">
<linktarget COLOR="#653e3f" DESTINATION="ID_1589656875" ENDARROW="Default" ENDINCLINATION="-142;905;" ID="Arrow_ID_1946206737" SOURCE="ID_676955985" STARTARROW="None" STARTINCLINATION="-388;-943;"/>
<node CREATED="1731846236310" ID="ID_1274731527" MODIFIED="1731846258272" TEXT="Basis-Template: RandomSequencer&lt;GEN&gt;">
<node CREATED="1731846283816" ID="ID_597020246" MODIFIED="1731846307669" TEXT="erzeugt aus SeedNucleus">
<linktarget COLOR="#8f8f94" DESTINATION="ID_597020246" ENDARROW="Default" ENDINCLINATION="112;0;" ID="Arrow_ID_138451619" SOURCE="ID_1530478572" STARTARROW="None" STARTINCLINATION="107;5;"/>
</node>
<node CREATED="1731846325776" ID="ID_324402112" MODIFIED="1731846334634" TEXT="alternativ: an bestehenden Generator angekoppelt"/>
<node CREATED="1731846395814" ID="ID_516539220" MODIFIED="1731846401666" TEXT="bietet direkt die Distributionen"/>
<node CREATED="1731857185006" ID="ID_1418948099" MODIFIED="1731857215216" TEXT="ist kopierbar und zuweisbar">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das ist ein Feature; man kann damit einen State speichern
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1731846402711" ID="ID_95043178" MODIFIED="1731846405385" TEXT="Distributionen">
<node CREATED="1731846489994" ID="ID_1252503451" MODIFIED="1731849013246" TEXT="integral">
<node CREATED="1731847162312" ID="ID_1919361587" MODIFIED="1731849022407" TEXT="Problem: Systematik f&#xfc;r die Grenzen">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1731847172007" ID="ID_1895536886" MODIFIED="1731847189328" TEXT="die STL macht beide Grenzen inclusiv">
<node CREATED="1731847666829" ID="ID_1876315451" MODIFIED="1731847672488" TEXT="aber nur f&#xfc;r Int-Distributionen"/>
<node CREATED="1731847673039" ID="ID_1584529207" MODIFIED="1731847681847" TEXT="f&#xfc;r Real-Distributionen ist die Obergrenze exclusiv"/>
</node>
<node CREATED="1731847190884" ID="ID_32994635" MODIFIED="1731847232730" TEXT="das ist &#xfc;berraschend / anders als rand()">
<node CREATED="1731847236786" ID="ID_1776740877" MODIFIED="1731847549026" TEXT="RAND_MAX &#x2261; 2^31 - 1"/>
<node CREATED="1731847551063" ID="ID_535434671" MODIFIED="1731847575965" TEXT="der Modulo-Trick erzeugt ebenfalls eine exclusive Obergrenze"/>
</node>
<node CREATED="1731847746013" ID="ID_1233650660" MODIFIED="1731847764663" TEXT="f&#xfc;r symmetrische und negative Wertbereiche w&#xe4;re das nat&#xfc;rlicher">
<node CREATED="1731847770056" ID="ID_477206568" MODIFIED="1731847788450" TEXT="aber diese treten erfahrungsgem&#xe4;&#xdf; selten auf"/>
<node CREATED="1731847789037" ID="ID_1733989680" MODIFIED="1731847797690" TEXT="wenn aber, sind sie stets verwirrend"/>
</node>
<node CREATED="1731847856612" ID="ID_1280577122" MODIFIED="1731847869366" TEXT="&#x27f9; das impliziert zwei Alternativen">
<node CREATED="1731847870455" ID="ID_1852724066" MODIFIED="1731847886660" TEXT="Untergrenze auf 0 fixieren und daf&#xfc;r die Obergrenze exclusiv"/>
<node CREATED="1731847888080" ID="ID_440496049" MODIFIED="1731847906945" TEXT="beide Grenzen konfigurierbar wie in der STL"/>
</node>
</node>
<node CREATED="1731851659080" ID="ID_527349814" MODIFIED="1731851691975" TEXT="Beschlu&#xdf;">
<node CREATED="1731851693013" ID="ID_1567706947" MODIFIED="1731851703374" TEXT="ich lege den auf int fest"/>
<node CREATED="1731851729695" ID="ID_288388982" MODIFIED="1731851739457" TEXT="[0 ... bound["/>
<node CREATED="1731851755307" ID="ID_670828588" MODIFIED="1731851762654" TEXT="Kurzer Name: i(bound)"/>
</node>
</node>
<node CREATED="1731847925115" ID="ID_1352182688" MODIFIED="1731848031027" TEXT="Design-Problem: Generator nicht zug&#xe4;nglich">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1731847939633" ID="ID_1582419047" MODIFIED="1731847956603" TEXT="ich m&#xf6;chte den (Roh)-Generator einpacken/verbergen"/>
<node CREATED="1731847957263" ID="ID_826907399" MODIFIED="1731847973232" TEXT="die STL geht (wie immer) genau den entgegengesetzten Weg"/>
<node CREATED="1731848012640" ID="ID_765417053" MODIFIED="1731848028489" TEXT="ein Grad an Kombinierbarkeit w&#xe4;re aber w&#xfc;nschenswert"/>
</node>
<node CREATED="1731848096704" ID="ID_322995053" MODIFIED="1731848105884" TEXT="Ausweg: generischer Zugang">
<icon BUILTIN="idea"/>
<node CREATED="1731848107195" ID="ID_969349228" MODIFIED="1731848118742" TEXT="distibute(DIST)">
<node CREATED="1731848122108" ID="ID_1399116407" MODIFIED="1731848139610" TEXT="nimmt ein Standard-Distribution-Object by-value"/>
<node CREATED="1731848140391" ID="ID_1345070881" MODIFIED="1731848166747" TEXT="zieht eine Zufallszahl und speist sie in dieses Objekt ein"/>
</node>
</node>
<node CREATED="1731851768409" ID="ID_64324165" MODIFIED="1731859635648" TEXT="Namen">
<icon BUILTIN="forward"/>
<node COLOR="#435e98" CREATED="1731851774145" ID="ID_357370370" MODIFIED="1731859631999" TEXT="distribute(DIST) : Basis-Impl: beliebige Dist"/>
<node COLOR="#435e98" CREATED="1731851801486" ID="ID_1612337960" MODIFIED="1731859631999" TEXT="i(bound) : drop-in-replacement f&#xfc;r rand()"/>
<node COLOR="#435e98" CREATED="1731851830060" ID="ID_944802289" MODIFIED="1731859631999" TEXT="i32() : voller Int-Bereich (incl. negative Zahlen)"/>
<node COLOR="#435e98" CREATED="1731851845839" ID="ID_1551621955" MODIFIED="1731859631998" TEXT="u64() : voller 64bit unsigned-Bereich"/>
<node COLOR="#435e98" CREATED="1731851888705" ID="ID_1032848952" MODIFIED="1731859631998" TEXT="uni() : uniform range [0 ... 1.0["/>
<node COLOR="#435e98" CREATED="1731851862876" ID="ID_1931647655" MODIFIED="1731859631998" TEXT="range(start, bound) : uniform range (double)"/>
<node COLOR="#435e98" CREATED="1731851915120" ID="ID_673952544" MODIFIED="1731859631997" TEXT="normal(mean, stdev) : Gau&#xdf;"/>
</node>
</node>
<node CREATED="1731851980917" ID="ID_915379812" MODIFIED="1731851987128" TEXT="convenience-free-functions">
<node COLOR="#435e98" CREATED="1731851988079" ID="ID_987128085" MODIFIED="1731859641027" TEXT="rani(bound) &#x27fc; defaultGen.i(bound)"/>
<node COLOR="#435e98" CREATED="1731852026551" ID="ID_122801033" MODIFIED="1731859641028" TEXT="ranRange &#x27fc; defaultGen.range"/>
<node COLOR="#435e98" CREATED="1731852036647" ID="ID_193693602" MODIFIED="1731859641028" TEXT="ranNormal &#x27fc; defaultGen.normal"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1731845842485" ID="ID_31813522" MODIFIED="1731859652771" TEXT="vorl&#xe4;ufige Einrichtung f&#xfc;r Tests....">
<arrowlink COLOR="#1a30c0" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="-284;-1132;" ID="Arrow_ID_1665212260" STARTARROW="None" STARTINCLINATION="-287;22;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1701698319632" ID="ID_883682364" MODIFIED="1701699545121" TEXT="Hash-Berechnung">
@ -57008,9 +57085,10 @@
<node COLOR="#435e98" CREATED="1729979325607" ID="ID_677674501" MODIFIED="1729979344958" TEXT="useFrameTable"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1730904143330" ID="ID_25783469" MODIFIED="1731205578435" TEXT="#1378 controlled random seed for tests">
<linktarget COLOR="#c4145f" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="6546;452;" ID="Arrow_ID_1019579428" SOURCE="ID_1500320757" STARTARROW="None" STARTINCLINATION="1769;146;"/>
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1730904143330" ID="ID_25783469" MODIFIED="1731864866245" TEXT="#1378 controlled random seed for tests">
<linktarget COLOR="#4514c4" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="6546;452;" ID="Arrow_ID_1019579428" SOURCE="ID_1500320757" STARTARROW="None" STARTINCLINATION="1769;146;"/>
<linktarget COLOR="#1a30c0" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="-284;-1132;" ID="Arrow_ID_1665212260" SOURCE="ID_31813522" STARTARROW="None" STARTINCLINATION="-287;22;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1730931170413" HGAP="34" ID="ID_480480032" MODIFIED="1731119671920" TEXT="diverse Zweifel &lt;random&gt; betreffend" VSHIFT="44">
<arrowlink COLOR="#968bb0" DESTINATION="ID_607929754" ENDARROW="Default" ENDINCLINATION="-1401;152;" ID="Arrow_ID_682771755" STARTARROW="None" STARTINCLINATION="-1300;91;"/>
<icon BUILTIN="messagebox_warning"/>
@ -57279,7 +57357,7 @@
</node>
</node>
</node>
<node CREATED="1731186827432" FOLDED="true" ID="ID_1343084270" MODIFIED="1731447211350" TEXT="nested Helper-Klassen f&#xfc;r Distributionen">
<node CREATED="1731186827432" FOLDED="true" ID="ID_1343084270" MODIFIED="1731844352255" TEXT="nested Helper-Klassen f&#xfc;r Distributionen">
<node CREATED="1731186885784" ID="ID_1137186891" MODIFIED="1731186909601" TEXT="sie bekommen optional einen Generator als ctor-Argument"/>
<node CREATED="1731186910274" ID="ID_1712434077" MODIFIED="1731186920709" TEXT="oder h&#xe4;ngen sich ansonsten an den default-Generator"/>
<node CREATED="1731186949918" ID="ID_1074918802" MODIFIED="1731187011177" TEXT="man k&#xf6;nnte das sp&#xe4;ter in ein Generatoren-Framework ausbauen">
@ -57350,7 +57428,7 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731424663557" ID="ID_1548490877" MODIFIED="1731447240469" TEXT="std::rand() ersetzen">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1731424663557" ID="ID_1548490877" MODIFIED="1731864831498" TEXT="std::rand() ersetzen">
<icon BUILTIN="yes"/>
<node COLOR="#435e98" CREATED="1731424676911" ID="ID_432733421" MODIFIED="1731447182287" TEXT="was wird ben&#xf6;tigt?">
<font NAME="SansSerif" SIZE="12"/>
@ -57437,7 +57515,8 @@
<node COLOR="#5b280f" CREATED="1731434364363" ID="ID_202795829" MODIFIED="1731434407298" TEXT="ranu und runi werden entfernt (zu sonderbar....)">
<icon BUILTIN="stop-sign"/>
</node>
<node CREATED="1731434034464" ID="ID_676955985" MODIFIED="1731434037208" TEXT="convenience">
<node CREATED="1731434034464" ID="ID_676955985" MODIFIED="1731859620136" TEXT="convenience">
<arrowlink COLOR="#653e3f" DESTINATION="ID_1589656875" ENDARROW="Default" ENDINCLINATION="-142;905;" ID="Arrow_ID_1946206737" STARTARROW="None" STARTINCLINATION="-388;-943;"/>
<node CREATED="1731434572056" ID="ID_1921841184" MODIFIED="1731434593712" TEXT="ranHash() &#x2260; 0"/>
<node CREATED="1731434043756" ID="ID_1935715464" MODIFIED="1731434328260" TEXT="ranRange(u,o) : double &#x2208; [u ... o[ "/>
<node CREATED="1731434161079" ID="ID_1433291868" MODIFIED="1731434333379" TEXT="ranNormal(&#x3bc; &#x2254;0.0, &#x3c3; &#x2254; 1.0) : Gau&#xdf;"/>
@ -57448,8 +57527,8 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1731434498664" ID="ID_33884738" MODIFIED="1731447066871" TEXT="Umstellung">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1731434498664" ID="ID_33884738" MODIFIED="1731864797092" TEXT="Umstellung">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1731434503085" ID="ID_779294881" MODIFIED="1731447063509" TEXT="API-Umstellungen">
<icon BUILTIN="button_ok"/>
</node>
@ -57462,7 +57541,7 @@
<node COLOR="#338800" CREATED="1731434548714" ID="ID_1401652131" MODIFIED="1731466845015" TEXT="rand() % MAX abl&#xf6;sen in Tests">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1731466845496" ID="ID_108595980" MODIFIED="1731466860399" TEXT="Tests scheitern nach Umstellung">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#690f14" CREATED="1731466845496" ID="ID_108595980" MODIFIED="1731864819581" TEXT="Tests scheitern nach Umstellung">
<icon BUILTIN="broken-line"/>
<node COLOR="#435e98" CREATED="1731466868785" ID="ID_1204988400" MODIFIED="1731516821863" TEXT="Rational_test">
<richcontent TYPE="NOTE"><html>
@ -58018,15 +58097,48 @@
<arrowlink COLOR="#73384b" DESTINATION="ID_1574698883" ENDARROW="Default" ENDINCLINATION="-9;41;" ID="Arrow_ID_1250752825" STARTARROW="None" STARTINCLINATION="34;4;"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731455444796" ID="ID_784243083" MODIFIED="1731455723202" TEXT="Concurrent Tests umstellen">
<icon BUILTIN="bell"/>
<node CREATED="1731728363475" ID="ID_1473702684" MODIFIED="1731728367146" TEXT="problematisch">
<node CREATED="1731455475587" ID="ID_1622000187" MODIFIED="1731455475587" TEXT="CallQueue_test"/>
<node CREATED="1731455716786" ID="ID_943344715" MODIFIED="1731455716786" TEXT="DiagnosticContext_test"/>
<node CREATED="1731458234804" ID="ID_1185469440" MODIFIED="1731458234804" TEXT="SessionCommandFunction_test"/>
<node CREATED="1731461928260" ID="ID_396786983" MODIFIED="1731461928260" TEXT="IncidenceCount_test"/>
<node CREATED="1731464404973" ID="ID_1534599775" MODIFIED="1731464404973" TEXT="SyncBarrier_test"/>
<node CREATED="1731464450346" ID="ID_1959292193" MODIFIED="1731464450346" TEXT="SyncClasslock_test"/>
<node COLOR="#338800" CREATED="1731455444796" ID="ID_784243083" MODIFIED="1731864793958" TEXT="Concurrent Tests umstellen">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#c8c0b6" CREATED="1731728363475" ID="ID_1473702684" MODIFIED="1731864804416" TEXT="problematisch">
<icon BUILTIN="info"/>
<node COLOR="#338800" CREATED="1731455716786" ID="ID_943344715" MODIFIED="1731864212381" TEXT="DiagnosticContext_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1731864232690" ID="ID_409271060" MODIFIED="1731864262374" TEXT="brauche nur einen Zufallswert &#x27f6; in die Closure binden">
<font NAME="SansSerif" SIZE="10"/>
</node>
</node>
<node COLOR="#338800" CREATED="1731455475587" ID="ID_1622000187" MODIFIED="1731860003292" TEXT="CallQueue_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1731861101886" HGAP="31" ID="ID_784906746" MODIFIED="1731864290533" TEXT="(Generator-Objekt in jeden Thread)" VSHIFT="2">
<arrowlink DESTINATION="ID_1185469440" ENDARROW="Default" ENDINCLINATION="57;5;" ID="Arrow_ID_403753001" STARTARROW="None" STARTINCLINATION="5;28;"/>
<arrowlink DESTINATION="ID_396786983" ENDARROW="Default" ENDINCLINATION="123;15;" ID="Arrow_ID_609954343" STARTARROW="None" STARTINCLINATION="0;41;"/>
<arrowlink DESTINATION="ID_1534599775" ENDARROW="Default" ENDINCLINATION="115;16;" ID="Arrow_ID_439192060" STARTARROW="None" STARTINCLINATION="12;89;"/>
<arrowlink DESTINATION="ID_444907234" ENDARROW="Default" ENDINCLINATION="43;7;" ID="Arrow_ID_259642088" STARTARROW="None" STARTINCLINATION="-8;32;"/>
<font NAME="SansSerif" SIZE="11"/>
</node>
</node>
<node COLOR="#338800" CREATED="1731465663005" ID="ID_444907234" MODIFIED="1731864283742" TEXT="BusTerm_test">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_444907234" ENDARROW="Default" ENDINCLINATION="43;7;" ID="Arrow_ID_259642088" SOURCE="ID_784906746" STARTARROW="None" STARTINCLINATION="-8;32;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731458234804" ID="ID_1185469440" MODIFIED="1731864290533" TEXT="SessionCommandFunction_test">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1185469440" ENDARROW="Default" ENDINCLINATION="57;5;" ID="Arrow_ID_403753001" SOURCE="ID_784906746" STARTARROW="None" STARTINCLINATION="5;28;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731461928260" ID="ID_396786983" MODIFIED="1731863340988" TEXT="IncidenceCount_test">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_396786983" ENDARROW="Default" ENDINCLINATION="123;15;" ID="Arrow_ID_609954343" SOURCE="ID_784906746" STARTARROW="None" STARTINCLINATION="0;41;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731464404973" ID="ID_1534599775" MODIFIED="1731863360009" TEXT="SyncBarrier_test">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1534599775" ENDARROW="Default" ENDINCLINATION="115;16;" ID="Arrow_ID_439192060" SOURCE="ID_784906746" STARTARROW="None" STARTINCLINATION="12;89;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731464450346" ID="ID_1959292193" MODIFIED="1731863580125" TEXT="SyncClasslock_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1731863556524" HGAP="27" ID="ID_708525528" MODIFIED="1731863570931" TEXT="use shared capped generator" VSHIFT="8">
<font NAME="SansSerif" SIZE="11"/>
</node>
</node>
<node COLOR="#5b280f" CREATED="1731464565589" ID="ID_864840738" MODIFIED="1731464568650" TEXT="SyncLocking_test">
<icon BUILTIN="button_cancel"/>
<node COLOR="#435e98" CREATED="1731464569588" HGAP="21" ID="ID_473912166" MODIFIED="1731464596488" TEXT="nein: der ist sauber" VSHIFT="1">
@ -58047,9 +58159,8 @@
<node CREATED="1731464903922" ID="ID_349618800" MODIFIED="1731464903922" TEXT="ThreadWrapperJoin_test"/>
</node>
</node>
<node CREATED="1731465663005" ID="ID_444907234" MODIFIED="1731465663005" TEXT="BusTerm_test"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1731728379707" ID="ID_38959317" MODIFIED="1731728399492" TEXT="gibt es &#xfc;berhaupt ein Problem hier?">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1731728379707" ID="ID_38959317" MODIFIED="1731809589226" TEXT="gibt es &#xfc;berhaupt ein Problem hier?">
<icon BUILTIN="help"/>
<node CREATED="1731728402020" ID="ID_216802866" MODIFIED="1731728433241" TEXT="theoretisch ist PRNG nicht thread-safe"/>
<node CREATED="1731728433837" ID="ID_975708385" MODIFIED="1731728441330" TEXT="aber ... was kann schon passieren??"/>
@ -58058,9 +58169,7 @@
<node CREATED="1731753438455" ID="ID_518457223" MODIFIED="1731753543440" TEXT="tats&#xe4;chlich auf meiner Maschine ist das unm&#xf6;glich (ulong &#x2261; uint64_t)"/>
<node CREATED="1731753607692" ID="ID_759994737" MODIFIED="1731753666983" TEXT="man k&#xf6;nnte das aber mit der &#xbb;kleinen&#xab; mersenne-Engine mt19937 untersuchen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
diese verwendet uint_fast32_t, das aber auf meinem System ebenfalls auf unit64_t gemapped ist
@ -58071,9 +58180,8 @@
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1731728584572" ID="ID_1568853077" MODIFIED="1731728594906" TEXT="empirisch untersuchen">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1731728584572" FOLDED="true" ID="ID_1568853077" MODIFIED="1731809658435" TEXT="empirisch untersuchen">
<icon BUILTIN="yes"/>
<icon BUILTIN="pencil"/>
<node CREATED="1731728599474" ID="ID_1952720762" MODIFIED="1731728615563" TEXT="mit allen Cores parallel Zufallszahlen ziehen"/>
<node CREATED="1731728616535" ID="ID_59784960" MODIFIED="1731728640632" TEXT="einzelne Zahlen pr&#xfc;fen"/>
<node CREATED="1731728641175" ID="ID_177314578" MODIFIED="1731728668212" TEXT="MIttelwert pr&#xfc;fen (bias)"/>
@ -58109,7 +58217,7 @@
<node CREATED="1731775985924" ID="ID_1953980277" MODIFIED="1731776143208" TEXT="sollte bei einer &#xbb;gesunden&#xab; Verteilung unter 30% liegen"/>
</node>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1731776150715" ID="ID_692908068" MODIFIED="1731776206608" TEXT="3. Test mit diversen Varianten &#x27f9; alle Generatoren betroffen">
<node BACKGROUND_COLOR="#e7c745" COLOR="#9b114a" CREATED="1731776150715" ID="ID_692908068" MODIFIED="1731809637025" TEXT="3. Test mit diversen Varianten &#x27f9; alle Generatoren betroffen">
<icon BUILTIN="stop-sign"/>
<node CREATED="1731776233760" ID="ID_47841503" MODIFIED="1731776309786" TEXT="sobald wir concurrent zugreifen, ist die Verteilung gest&#xf6;rt">
<icon BUILTIN="forward"/>
@ -58127,9 +58235,7 @@
</node>
<node CREATED="1731777433204" ID="ID_1308403781" MODIFIED="1731777549795" TEXT="...die Inzidenz h&#xe4;ngt stark von Umst&#xe4;nden ab">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
schon kleine &#196;nderungen in der Payload-Funktion k&#246;nnen die Inzidenz der Probleme drastisch &#228;ndern; beispielsweise hat das Hinzuf&#252;gen einer Begrenzung per Modulo f&#252;r einen Generator die Inzidenz drastisch erh&#246;ht, f&#252;r einen anderen die Probleme nahezu zum Verschwinden gebracht
@ -58147,16 +58253,22 @@
<node CREATED="1731777687774" ID="ID_1782576024" MODIFIED="1731777736651" TEXT="da zudem eine direkte Kollision nicht so h&#xe4;ufig ist, kann man die Thematik u.U. dann ignorieren"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1731781569046" ID="ID_1384257142" MODIFIED="1731781583030" TEXT="diese Me&#xdf;-Anordnung in einen sch&#xf6;nen Test verpacken....">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1731781569046" ID="ID_1384257142" MODIFIED="1731809512163" TEXT="diese Me&#xdf;-Anordnung in einen sch&#xf6;nen Test verpacken....">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1731781586201" ID="ID_239188866" MODIFIED="1731781593281" TEXT="tabellarische Ausgabe">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1731781594017" ID="ID_951906840" MODIFIED="1731781601504" TEXT="Statistik automatisch bewerten">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1731781602363" ID="ID_1537588023" MODIFIED="1731781608615" TEXT="kommentieren / erl&#xe4;utern">
<icon BUILTIN="flag-pink"/>
<node COLOR="#338800" CREATED="1731809497409" ID="ID_1000378102" MODIFIED="1731809509830" TEXT="bei der Gelegenheit auch ein Benchmark">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1731809518948" ID="ID_1436222406" MODIFIED="1731809569847" TEXT="std::rand: 15ns | 19ns (O3)"/>
<node COLOR="#435e98" CREATED="1731809534065" ID="ID_110429664" MODIFIED="1731809569849" TEXT="mersenne: 45ns | 25ns"/>
<node COLOR="#435e98" CREATED="1731809551526" ID="ID_1283714600" MODIFIED="1731809569849" TEXT="/dev/urandom: 480ns stets"/>
</node>
<node COLOR="#338800" CREATED="1731781602363" ID="ID_1537588023" MODIFIED="1731809510922" TEXT="kommentieren / erl&#xe4;utern">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1731777769395" ID="ID_1256945696" MODIFIED="1731781639135" TEXT="es gibt also drei Ans&#xe4;tze">
@ -58172,8 +58284,8 @@
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731781708768" ID="ID_819976783" MODIFIED="1731781729751" TEXT="Konsequenz &#x27f9; Template bereitstellen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1731781708768" ID="ID_819976783" MODIFIED="1731809667057" TEXT="Konsequenz &#x27f9; Template bereitstellen">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1731777778369" ID="ID_689903625" MODIFIED="1731781689836" TEXT="jedem Thread wirklich seinen eigenen Generator geben">
@ -92682,7 +92794,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#77313e" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="381;-48;" ID="Arrow_ID_1047269362" SOURCE="ID_936086670" STARTARROW="None" STARTINCLINATION="-36;80;"/>
<linktarget COLOR="#6f2328" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="366;-47;" ID="Arrow_ID_1067356199" SOURCE="ID_683548249" STARTARROW="None" STARTINCLINATION="5;52;"/>
<icon BUILTIN="pencil"/>
<node CREATED="1730900637026" ID="ID_1500320757" MODIFIED="1730904275397" TEXT="brauche Einflu&#xdf; auf den PRNG">
<node CREATED="1730900637026" ID="ID_1500320757" MODIFIED="1731864860121" TEXT="brauche Einflu&#xdf; auf den PRNG">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -92691,7 +92803,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#c4145f" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="6546;452;" ID="Arrow_ID_1019579428" STARTARROW="None" STARTINCLINATION="1769;146;"/>
<arrowlink COLOR="#4514c4" DESTINATION="ID_25783469" ENDARROW="Default" ENDINCLINATION="6546;452;" ID="Arrow_ID_1019579428" STARTARROW="None" STARTINCLINATION="1769;146;"/>
</node>
<node CREATED="1730900645921" ID="ID_1469990348" MODIFIED="1730901263434" TEXT="brauche Umstellung des Headers">
<richcontent TYPE="NOTE"><html>
@ -139082,15 +139194,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1710186359368" ID="ID_765629285" MODIFIED="1710186365813" TEXT="Info">
<icon BUILTIN="info"/>
<node CREATED="1710186277136" ID="ID_336649935" LINK="https://en.cppreference.com/w/cpp/numeric/random" MODIFIED="1710186690629" TEXT="Standard-Lib: (pseudo)-random number generation"/>
<node CREATED="1730916530347" FOLDED="true" ID="ID_607929754" MODIFIED="1731115515196" TEXT="Probleme / Diskussion">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
&#160;
</p>
</body>
</html></richcontent>
<node CREATED="1730916530347" FOLDED="true" ID="ID_607929754" MODIFIED="1731868515865" TEXT="Probleme / Diskussion">
<linktarget COLOR="#968bb0" DESTINATION="ID_607929754" ENDARROW="Default" ENDINCLINATION="-1401;152;" ID="Arrow_ID_682771755" SOURCE="ID_480480032" STARTARROW="None" STARTINCLINATION="-1300;91;"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1730916541434" ID="ID_1186515484" MODIFIED="1730916550532" TEXT="nicht klar wie man &#xbb;korrekt&#xab; seeded">
@ -139169,11 +139273,16 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1730923153709" ID="ID_1131418575" LINK="https://www.reddit.com/r/cpp/comments/ecrnjl/can_we_do_better_than_the_mersenne_twister/" MODIFIED="1730924006139" TEXT="&quot;can we do better than mersenne?&quot;">
<node CREATED="1730924010003" ID="ID_406338445" LINK="https://burtleburtle.net/bob/rand/smallprng.html" MODIFIED="1730924059005" TEXT="Jenkins"/>
<node CREATED="1730924013155" ID="ID_1112820214" LINK="https://pracrand.sourceforge.net/RNG_engines.txt" MODIFIED="1730924281091" TEXT="PractRand"/>
<node CREATED="1731866839783" ID="ID_751896062" LINK="http://prng.di.unimi.it/" MODIFIED="1731866863658" TEXT="Xoroshiro">
<linktarget COLOR="#4499cd" DESTINATION="ID_751896062" ENDARROW="Default" ENDINCLINATION="124;-17;" ID="Arrow_ID_326929346" SOURCE="ID_472584641" STARTARROW="None" STARTINCLINATION="70;-69;"/>
</node>
<node CREATED="1730926918445" ID="ID_595255954" LINK="https://www.pcg-random.org/" MODIFIED="1730927175433" TEXT="PCG-Random">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_595255954" ENDARROW="Default" ENDINCLINATION="228;0;" ID="Arrow_ID_1247304219" SOURCE="ID_1870117805" STARTARROW="None" STARTINCLINATION="228;25;"/>
<node CREATED="1730929577122" HGAP="24" ID="ID_1482800255" MODIFIED="1730929596392" TEXT="ist ein Hobby-Projekt von ihr" VSHIFT="18"/>
<node CREATED="1730929582849" ID="ID_340137516" MODIFIED="1730929590956" TEXT="besteht den PractRand-Test"/>
<node CREATED="1730940355738" ID="ID_472584641" LINK="https://pcg.di.unimi.it/pcg.php" MODIFIED="1730940454177" TEXT="fachliche Kontroverse zwischen Melissa O&apos;Neill und Sebastiano Vigna"/>
<node CREATED="1730940355738" ID="ID_472584641" LINK="https://pcg.di.unimi.it/pcg.php" MODIFIED="1731866868915" TEXT="fachliche Kontroverse zwischen Melissa O&apos;Neill und Sebastiano Vigna">
<arrowlink COLOR="#4499cd" DESTINATION="ID_751896062" ENDARROW="Default" ENDINCLINATION="124;-17;" ID="Arrow_ID_326929346" STARTARROW="None" STARTINCLINATION="70;-69;"/>
</node>
</node>
</node>
</node>