Как позволить Boost :: random и Matlab генерировать одинаковые случайные числа - PullRequest
4 голосов
/ 29 апреля 2011

Чтобы проверить мой код 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', 'seed', 203)); rand (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 ++ Boost

0.8479 0.667228 0.188938 0.715892 0.450607 0.0790326 0.625347 0.972369 0.969748 0.858771

То же самое, что и любое другое значение Python и Matlab ...

Ответы [ 5 ]

4 голосов
/ 29 апреля 2011

Используя интерфейс как

randi(6,1,10)

применяет какое-то преобразование к необработанному результату генератора случайных чисел. Это преобразование является не тривиальным в общем , и Matlab почти наверняка сделает шаг выбора, отличный от Boost.

Попробуйте сравнить необработанные потоки данных от ГСЧ - скорее всего, они одинаковы

4 голосов
/ 29 апреля 2011

Я должен согласиться с другими ответами, заявив, что эти генераторы не являются «абсолютными».Они могут давать разные результаты в зависимости от реализации.Я думаю, что самым простым решением было бы реализовать собственный генератор.Это может выглядеть пугающе (кстати, твистер Мерсенна, кстати), но взгляните на 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 ++ используют оба 32-битных для этих беззнаковых int.

3 голосов
/ 13 сентября 2012

В случае, если это поможет всем, кто интересуется вопросом:

Чтобы получить то же поведение для алгоритма Твистера:

  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 )

1 голос
/ 18 сентября 2014

Благодаря ответу Фезвеза я написал xor128 в matlab:

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 каждый раз, когда вы его используете.Я написал функцию «тестер», которая просто возвращает вектор со случайными числами.Я проверил 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
0 голосов
/ 29 апреля 2011

Я бы очень осторожно предположил, что две разные реализации псевдослучайных генераторов (даже если они основаны на одних и тех же алгоритмах) дают одинаковый результат.Может быть, что одна из реализаций использует какую-то настройку, что приводит к разным результатам.Если вам нужны два одинаковых «случайных» дистрибутива, я предлагаю вам либо пересчитать последовательность, сохранить и получить доступ как из C ++, так и из Matlab или создать свой собственный генератор.Внедрение MT19937 должно быть достаточно простым, если вы используете псевдокод в Wikipedia .

Убедитесь, что ваш код Matlab и C ++ работает на одной и той же архитектуре (то есть оба работают на32-разрядное или 64-разрядное) - использование 64-разрядного целого в одной реализации и 32-разрядного целого в другой приведет к различным результатам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...