Последовательная генерация случайных чисел на разных платформах с boost::random

Мы уже некоторое время используем boost::random в наших проектах. Недавно неработающий тестовый модуль заинтриговал меня одним из его свойств: последовательность чисел, генерируемых в разных версиях Boost, может различаться в зависимости от используемого дистрибутива.

Такое поведение не представляется согласованным во всех дистрибутивах. В большинстве случаев равномерное распределение с использованием ГСЧ с одинаковыми затравками дает одинаковые результаты. Другие распределения, такие как normal, lognormal, binomial а также discrete может показать эти различия.

Я собрал простую программу на C++, которая показывает проблему:

#include <iostream>
#include <boost/random.hpp>
#include <stdint.h>

void uniform() {
  uint32_t seed = 42;
  boost::mt19937 rng(seed);
  boost::random::uniform_real_distribution<double> distro(0., 1.);
  std::cout << "uniform" << std::endl;
  for (int i=0; i<10; ++i) {
    std::cout << distro(rng) << std::endl;
  }
}

void normal() {
  uint32_t seed = 42;
  boost::mt19937 rng(seed);
  boost::random::normal_distribution<double> distro(0., 1.);
  std::cout << "normal" << std::endl;
  for (int i=0; i<10; ++i) {
    std::cout << distro(rng) << std::endl;
  }
}

void discrete() {
  uint32_t seed = 42;
  boost::mt19937 rng(seed);
  std::vector<double> P;
  P.push_back(0.3);
  P.push_back(0.4);
  P.push_back(0.3);
  boost::random::discrete_distribution<uint64_t> distro(P.begin(), P.end());
  std::cout << "discrete" << std::endl;
  for (int i=0; i<10; ++i) {
    std::cout << distro(rng) << std::endl;
  }
}

int main() {
  uniform();
  normal();
  discrete();
}

Эта простая программа покажет разные последовательности чисел для Boost 1.56 (работает на OSX):

uniform
0.37454
0.796543
0.950714
0.183435
0.731994
0.779691
0.598658
0.59685
0.156019
0.445833
normal
-0.638714
-0.836808
-0.400566
-0.869232
-0.972045
-0.758932
-1.30435
1.22996
0.249399
0.286848
discrete
1
2
2
1
0
0
0
2
1
2

Или с Boost 1.50 (работает на Ubuntu 12.10):

uniform
0.37454
0.796543
0.950714
0.183435
0.731994
0.779691
0.598658
0.59685
0.156019
0.445833
normal
-1.25821
1.2655
0.606347
-0.19401
-0.196366
-1.72826
-1.09713
-0.783069
0.604964
0.90255
discrete
2
1
2
1
1
0
1
1
0
1

Обратите внимание, что равномерное распределение работает, как и ожидалось: то есть одно и то же начальное число генерирует согласованную последовательность чисел в обеих версиях. Нормальное и дискретное распределение не ведут себя одинаково.

Есть ли способ "исправить" это? Т.е. у разных платформ генерируется одинаковая последовательность независимо от буст версии?

1 ответ

Решение

Кажется, что boost::random не гарантирует, что вы получите одинаковую последовательность чисел для определенных семян с разными версиями boost.

Например, в версии 1.56 они изменили алгоритм генерации случайных чисел с нормальным распределением из метода Бокса-Мюллера в метод Зиккурата:

https://github.com/boostorg/random/commit/f0ec97ba36c05ef00f2d29dcf66094e3f4abdcde

Этот метод быстрее, но также производит различные числовые последовательности.

Подобные изменения, вероятно, были сделаны в других дистрибутивах. Равномерное распределение по-прежнему дает тот же результат, что и обычно вывод базового rng, который по умолчанию является мерсенновым твистером 19937.

Другие вопросы по тегам