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

时间:2011-04-29 07:58:22

标签: c++ matlab boost

要检查我的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值相同......

5 个答案:

答案 0 :(得分:4)

使用

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

将对随机生成器的原始结果应用某种转换。这种转换 is not trivial in general 和Matlab几乎肯定会做出与Boost不同的选择步骤。

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

答案 1 :(得分:4)

我必须同意其他答案,并指出这些发电机不是“绝对的”。根据实施,它们可能产生不同的结果。我认为最简单的解决方案是实现自己的生成器。它可能看起来令人生畏(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));
}

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

答案 2 :(得分:3)

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

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

  1. 下载文件 http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/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("%.20f\n",genrand_res53());
        return 0;
    }
    
  3. 确保在matlab中生成相同的值:

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

答案 3 :(得分:1)

感谢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。我写了一个&#34;测试员&#34;只返回带有随机数的向量的函数。我测试了这个函数输出的1000个数字对cpp和gcc输出的值,它是完美的。

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

答案 4 :(得分:0)

我会非常小心地假设伪随机生成器的两种不同实现(即使基于相同的算法)产生相同的结果。可能有一个实现使用某种调整,因此产生不同的结果。如果您需要两个相等的“随机”分布,我建议您预先计算序列,存储和访问C ++和Matlab,或者创建自己的生成器。如果在Wikipedia上使用伪代码,那么实现MT19937应该相当容易。

注意确保Matlab和C ++代码在相同的体系结构上运行(即,无论是在32位还是64位上运行) - 在一个实现中使用64位整数,在另一个实现中使用32位整数导致不同的结果。