如何让Boost::random和Matlab产生相同的随机数

How to let Boost::random and Matlab produce the same random numbers

本文关键字:随机数 Boost random Matlab      更新时间:2023-10-16

检查我的c++代码,我希望能够让Boost::Random和Matlab产生相同的随机数。

对于Boost,我使用代码:

boost::mt19937 var(static_cast<unsigned> (std::time(0)));
boost::uniform_int<> dist(1, 6);
boost::variate_generator<boost::mt19937&, boost::uniform_int<> > die(var, dist);
die.engine().seed(0);     
for(int i = 0; i < 10; ++i) {
    std::cout << die() << " ";
}      
std::cout    << std::endl;

生成(每次运行程序):
4 4 5 6 4 6 4 6 3 4

对于matlab,我使用:

RandStream.setDefaultStream(RandStream('mt19937ar','seed',0));
randi(6,1,10)

生成(每次运行程序):
5 6 1 6 4 1 2 4 6 6

这很奇怪,因为两者使用相同的算法和相同的种子。我错过了什么?

似乎Python(使用numpy)和Matlab在随机均匀数方面具有可比性:Matlab

RandStream.setDefaultStream (RandStream(‘mt19937ar’,‘种子’,203));兰德(1,10)

0.8479 0.1889 0.4506 0.6253 0.9697 0.2078 0.5944 0.9115 0.2457 0.7743

Python:random.seed (203); random.random (10)

array([ 0.84790006, 0.18893843, 0.45060688, 0.62534723, 0.96974765, 0.20780668, 0.59444858, 0.91145688, 0.24568615, 0.77430378])

c++提高

0.8479 0.667228 0.188938 0.715892 0.450607 0.0790326 0.625347 0.972369 0.969748 0.858771

这是相同的任何其他Python和Matlab值…

我不得不同意其他答案,说明这些生成器不是"绝对的"。它们可能根据实施产生不同的结果。我认为最简单的解决方案是实现自己的生成器。它可能看起来令人生畏(顺便说一下,Mersenne twister当然是),但看看Xorshift,一个极其简单但功能强大的工具。我复制了维基百科链接中给出的C实现:

uint32_t xor128(void) {
  static uint32_t x = 123456789;
  static uint32_t y = 362436069;
  static uint32_t z = 521288629;
  static uint32_t w = 88675123;
  uint32_t t;
  t = x ^ (x << 11);
  x = y; y = z; z = w;
  return w = w ^ (w >> 19) ^ (t ^ (t >> 8));
}

要拥有相同的种子,只需将您想要的任何值放入x,y,z,w(我相信除了(0,0,0,0))。您只需要确保Matlab和c++对这些unsigned int都使用32位。

使用像

这样的界面
randi(6,1,10)

将对随机生成器的原始结果应用某种转换。这个变换一般来说不是微不足道的,并且Matlab几乎肯定会执行与Boost不同的选择步骤。

尝试比较来自rng的原始数据流-它们很可能是相同的

如果这对任何对这个问题感兴趣的人有帮助:

为了获得与Twister算法相同的行为:

  1. 下载文件http://www.math.sci.hiroshima-u.ac.jp/m-mat每公吨/MT2002/编码/mt19937ar.c

  2. 尝试如下:

    #include <stdint.h>
    // mt19937ar.c content..
    int main(void)
    {
        int i;
        uint32_t seed = 100;
        init_genrand(seed);
        for (i = 0; i < 100; ++i)
            printf("%.20fn",genrand_res53());
        return 0;
    }
    
  3. 确保在matlab中生成相同的值:

    RandStream.setGlobalStream( RandStream.create('mt19937ar','seed',100) );
    rand(100,1)
    
  4. randi()似乎只是ceil( rand()*maxval )

感谢Fezvez的回答,我已经用matlab编写了xor128:

function [ w, state ] = xor128( state )
%XOR128 implementation of Xorshift
%   https://en.wikipedia.org/wiki/Xorshift
%   A starting state might be [123456789, 362436069, 521288629, 88675123]
  x = state(1);
  y = state(2);
  z = state(3);
  w = state(4);
  % t1 = (x << 11)
  t1 = bitand(bitshift(x,11),hex2dec('ffffffff'));
  % t = x ^ (x << 11)
  t = bitxor(x,t1);
  x = y;
  y = z;
  z = w;
  % t2 = (t ^ (t >> 8))
  t2 = bitxor(t, bitshift(t,-8));
  % t3 = w ^ (w >> 19)
  t3 = bitxor(w, bitshift(w,-19));
  % w = w ^ (w >> 19) ^ (t ^ (t >> 8))
  w = bitxor(t3, t2);
  state = [x y z w];
end

每次使用时都需要将状态传递给xor128。我编写了一个"tester"函数,它只是返回一个带有随机数的向量。我用gcc测试了这个函数输出的1000个数字与cpp输出的值,它是完美的。

function [ v ] = txor( iterations )
%TXOR test xor128, returns vector v of length iterations with random number
% output from xor128
% output
v = zeros(iterations,1);
state = [123456789, 362436069, 521288629, 88675123];

i = 1;
while i <= iterations
    disp(i);
    [t,state] = xor128(state);
    v(i) = t;
    i = i + 1;
end

假设伪随机生成器的两种不同实现(即使基于相同的算法)产生相同的结果,我会非常小心。可能其中一个实现使用了某种调整,从而产生不同的结果。如果你需要两个相等的"随机"分布,我建议你要么预先计算一个序列,从c++和Matlab存储和访问,要么创建你自己的生成器。如果您使用维基百科上的伪代码,实现MT19937应该相当容易。

注意确保您的Matlab和c++代码在相同的体系结构上运行(即,两者都运行在32位或64位上)-在一个实现中使用64位整数,在另一个实现中使用32位整数将导致不同的结果。