in reply to Re: Mersenne Twister
in thread Mersenne Twister

I guess I was hoping for something a little less obfuscated. My perl is a little rusty... I'd settle for some good pseudocode.

Replies are listed 'Best First'.
Re^3: Mersenne Twister
by marto (Cardinal) on Jan 05, 2024 at 17:15 UTC

    The module source hasn't been obfuscated, perhaps you're looking for some pseudocode for the algorithm? Your search engine of choice can help you out there.

Re^3: Mersenne Twister
by karlgoethebier (Abbot) on Jan 06, 2024 at 11:11 UTC

    ”…pseudocode…”

    Stolen from here. If it’s good is another question.

    // Create a length n array to store the state of the generator int[0..n-1] MT int index := n+1 const int lower_mask = (1 << r) - 1 // That is, the binary number of +r 1's const int upper_mask = lowest w bits of (not lower_mask) // Initialize the generator from a seed function seed_mt(int seed) { index := n MT[0] := seed for i from 1 to (n - 1) { // loop over each element MT[i] := lowest w bits of (f * (MT[i-1] xor (MT[i-1] >> (w-2) +)) + i) } } // Extract a tempered value based on MT[index] // calling twist() every n numbers function extract_number() { if index >= n { if index > n { error "Generator was never seeded" // Alternatively, seed with constant value; 5489 is used in + reference C code[54] } twist() } int y := MT[index] y := y xor ((y >> u) and d) y := y xor ((y << s) and b) y := y xor ((y << t) and c) y := y xor (y >> l) index := index + 1 return lowest w bits of (y) } // Generate the next n values from the series x_i function twist() { for i from 0 to (n-1) { int x := (MT[i] and upper_mask) | (MT[(i+1) mod n] and lower_mask) int xA := x >> 1 if (x mod 2) != 0 { // lowest bit of x is 1 xA := xA xor a } MT[i] := MT[(i + m) mod n] xor xA } index := 0 }

    «The Crux of the Biscuit is the Apostrophe»

Re^3: Mersenne Twister
by karlgoethebier (Abbot) on Jan 07, 2024 at 11:19 UTC
Re^3: Mersenne Twister
by harangzsolt33 (Deacon) on Jan 05, 2024 at 21:25 UTC

      The Mersenne Twister is a popular pseudo-random number generator (PRNG) because it has good distribution properties and a long period length (2^19937 - 1) before the sequence repeats. It passes all the diehard tests of randomness, and nearly all of the TestUO1 tests. (Wikipedia is a reasonable source of info for this: https://en.wikipedia.org/wiki/Mersenne_Twister).

      The algorithm you describe is a Linear Congruential Generator (LCG). These have global correlation structures that cause issues at the square root or cubed root of the period length.

      Perl's rand() uses the drand48 algorithm on all operating systems since 5.20 (https://metacpan.org/release/RJBS/perl-5.20.0/view/pod/perldelta.pod#rand-now-uses-a-consistent-random-number-generator). This has a longer period length (2^48) than the standard ANSI C rand (2^31) but is still an LCG and thus has issues with correlation structures. Some useful illustrations are at https://wellington.pm.org/archive/200704/randomness/index.html, for example slide7, slide8 and slide 14.

      Whether all the above matters depends on the application. If it is just selecting from a small pool of items a small number of times then the choice of PRNG is unlikely to be an issue. Applications with larger data sets require better quality PRNGs.

        "since 5.20"

        Hmm... Interesting. That's good to know... I have been using TinyPerl 5.8 mostly. When plotting random lines, I did notice that there is a visible difference or should I say "resemblance of a pattern" visible with what you mentioned, LCG, but when I plotted lines with Mersenne Twister, the lines appeared completely random.