免责声明:我不确定从任意“uint”(或 x,其中 x 是较小的任意但唯一值)种子开始时,MT 在循环重叠方面有什么保证,但这可能值得研究,好像有是一个保证,那么只需在不同的“uint”种子上启动每个节点就足够了,而这篇文章的其余部分在很大程度上变得没有意义。(MT 的周期长度/周期是惊人的,除以 UINT_MAX 仍然留下一个难以理解的数字——除了在纸上——数字。)
好吧,这里是我的评论来回答......
我喜欢方法#2,它带有一组预先生成的状态;然后用给定的起始状态初始化每个节点中的 MT。
当然,只有初始状态必须保留,一旦生成,这些状态就可以
- 如果满足要求,可以无限期地重复使用,或者;
- 下一个状态可以在模拟运行的外部快速框上向前生成,或者;
- 节点可以报告结束状态(如果可靠的消息传递,以及是否在节点之间以相同的速率使用序列,并且满足要求等)
考虑到 MT 的生成速度很快,我不推荐上面的#3,因为它很复杂并且附带了许多字符串。选项 #1 很简单,但可能不够动态。
选项#2 似乎是一个很好的可能性。服务器(“快速机器”,不一定是节点)只需要传输下一个“未使用序列块”的起始状态(比如十亿个周期)——节点会在询问之前使用生成器十亿个周期对于一个新块。这将使它成为帖子中#1 的混合体,并且消息很少。
在我的系统 Core2 Duo 上,我可以使用下面提供的代码在 17 秒内生成十亿个随机数(它在LINQPad中运行)。我不确定这是什么 MT 变体。
void Main()
{
var mt = new MersenneTwister();
var start = DateTime.UtcNow;
var ct = 1000000000;
int n = 0;
for (var i = 0; i < ct; i++) {
n = mt.genrand_int32();
}
var end = DateTime.UtcNow;
(end - start).TotalSeconds.Dump();
}
// From ... and modified (stripped) to work in LINQPad.
// http://mathnet-numerics.googlecode.com/svn-history/r190/trunk/src/Numerics/Random/MersenneTwister.cs
// See link for license and copyright information.
public class MersenneTwister
{
private const uint _lower_mask = 0x7fffffff;
private const int _m = 397;
private const uint _matrix_a = 0x9908b0df;
private const int _n = 624;
private const double _reciprocal = 1.0/4294967295.0;
private const uint _upper_mask = 0x80000000;
private static readonly uint[] _mag01 = {0x0U, _matrix_a};
private readonly uint[] _mt = new uint[624];
private int mti = _n + 1;
public MersenneTwister() : this((int) DateTime.Now.Ticks)
{
}
public MersenneTwister(int seed)
{
init_genrand((uint)seed);
}
private void init_genrand(uint s)
{
_mt[0] = s & 0xffffffff;
for (mti = 1; mti < _n; mti++)
{
_mt[mti] = (1812433253*(_mt[mti - 1] ^ (_mt[mti - 1] >> 30)) + (uint) mti);
_mt[mti] &= 0xffffffff;
}
}
public uint genrand_int32()
{
uint y;
if (mti >= _n)
{
int kk;
if (mti == _n + 1) /* if init_genrand() has not been called, */
init_genrand(5489); /* a default initial seed is used */
for (kk = 0; kk < _n - _m; kk++)
{
y = (_mt[kk] & _upper_mask) | (_mt[kk + 1] & _lower_mask);
_mt[kk] = _mt[kk + _m] ^ (y >> 1) ^ _mag01[y & 0x1];
}
for (; kk < _n - 1; kk++)
{
y = (_mt[kk] & _upper_mask) | (_mt[kk + 1] & _lower_mask);
_mt[kk] = _mt[kk + (_m - _n)] ^ (y >> 1) ^ _mag01[y & 0x1];
}
y = (_mt[_n - 1] & _upper_mask) | (_mt[0] & _lower_mask);
_mt[_n - 1] = _mt[_m - 1] ^ (y >> 1) ^ _mag01[y & 0x1];
mti = 0;
}
y = _mt[mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680;
y ^= (y << 15) & 0xefc60000;
y ^= (y >> 18);
return y;
}
}
快乐编码。