Skip to content

Commit 45c515f

Browse files
committed
Add 64-bit implementation of MersenneTwisterEngine
With the required tempering parameter `d` introduced by the previous patch, we can now introduce the standard 64-bit implementation of the Mersenne Twister. See https://en.wikipedia.org/wiki/Mersenne_Twister for an explanation of the chosen constants. Some minimal unittests have been added similar to those already present for the 32-bit `Mt19937`. These can be verified by comparison to C++11 by compiling and running the following C++ program: /****************************************************************/ int main () { static_assert(std::mt19937_64::default_seed == 5489, "Default seed does not match Phobos!"); std::mt19937_64 gen(std::mt19937_64::default_seed); std::cout << gen() << std::endl; for (int i = 0; i < 9998; ++i) { gen(); } std::cout << gen() << std::endl; } /****************************************************************/ Note that the `for` loop in this example advances the generator 9998 times compared to the D unittest's `popFrontN(9999)` because the first `gen()` call already advances the generator once. Fixes Issue #10900 <https://issues.dlang.org/show_bug.cgi?id=10900>.
1 parent dcd83ac commit 45c515f

File tree

1 file changed

+44
-1
lines changed

1 file changed

+44
-1
lines changed

std/random.d

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,49 @@ alias Mt19937 = MersenneTwisterEngine!(uint, 32, 624, 397, 31,
860860
assert(gen.front == 165737292u);
861861
}
862862

863+
/**
864+
A $(D MersenneTwisterEngine) instantiated with the parameters of the
865+
original engine $(HTTP en.wikipedia.org/wiki/Mersenne_Twister,
866+
MT19937-64), generating uniformly-distributed 64-bit numbers with a
867+
period of 2 to the power of 19937.
868+
*/
869+
alias Mt19937_64 = MersenneTwisterEngine!(ulong, 64, 312, 156, 31,
870+
0xb5026f5aa96619e9, 29, 0x5555555555555555, 17,
871+
0x71d67fffeda60000, 37,
872+
0xfff7eee000000000, 43, 6364136223846793005);
873+
874+
///
875+
@safe unittest
876+
{
877+
// Seed with a constant
878+
auto gen = Mt19937_64(12345);
879+
auto n = gen.front; // same for each run
880+
// Seed with an unpredictable value
881+
gen.seed(unpredictableSeed);
882+
n = gen.front; // different across runs
883+
}
884+
885+
@safe nothrow unittest
886+
{
887+
import std.algorithm;
888+
import std.range;
889+
static assert(isUniformRNG!Mt19937_64);
890+
static assert(isUniformRNG!(Mt19937_64, ulong));
891+
static assert(isSeedable!Mt19937_64);
892+
static assert(isSeedable!(Mt19937_64, ulong));
893+
// FIXME: this test demonstrates viably that Mt19937_64
894+
// is seedable with an infinite range of `ulong` values
895+
// but it's a poor example of how to actually seed the
896+
// generator, since it can't cover the full range of
897+
// possible seed values. Ideally we need a 64-bit
898+
// unpredictable seed to complement the 32-bit one!
899+
static assert(isSeedable!(Mt19937_64, typeof(map!((a) => (cast(ulong)unpredictableSeed))(repeat(0)))));
900+
Mt19937_64 gen;
901+
assert(gen.front == 14514284786278117030uL);
902+
popFrontN(gen, 9999);
903+
assert(gen.front == 9981545732273789042uL);
904+
}
905+
863906
@safe unittest
864907
{
865908
import std.exception;
@@ -895,7 +938,7 @@ alias Mt19937 = MersenneTwisterEngine!(uint, 32, 624, 397, 31,
895938
{
896939
import std.range;
897940
// Check .save works
898-
foreach (Type; std.meta.AliasSeq!(Mt19937))
941+
foreach (Type; std.meta.AliasSeq!(Mt19937, Mt19937_64))
899942
{
900943
auto gen1 = Type(unpredictableSeed);
901944
auto gen2 = gen1.save;

0 commit comments

Comments
 (0)