Распределение случайных чисел C ++ 11 не согласовано на разных платформах, какие есть альтернативы?

Я ищу набор переносимых дистрибутивов для стандартных движков C ++ 11, таких как `std :: mt19937 '(см. http://en.cppreference.com/w/cpp/numeric/random).

Реализации движка работают согласованно (то есть одна и та же последовательность, сгенерированная на разных платформах - протестировано с помощью Clang и MSVC), но дистрибутивы, похоже, реализованы по-разному на разных платформах.

Таким образом, даже несмотря на то, что движки выдают одну и ту же последовательность, кажется, что дистрибутив (например, std::normal_distribution<double>) не использует одинаковое количество выборок (т.е. дает разные результаты) на разных платформах, что в моем случае неприемлемо.

Может быть, я могу использовать стороннюю библиотеку, которая следует случайным шаблонам C ++ 11, но будет предоставлять согласованные значения на популярных платформах (с учетом поддержки GCC, MSVC и Clang / llvm).

Я рассмотрел следующие варианты:

  • Boost.random (немного тяжелый, но стоящий, поскольку он достаточно хорошо соответствует аналогам С ++ 11)
  • Клонирование из libstd ++ (также целесообразно и, вероятно, переносимо, но извлечение определенных функций может оказаться непростым делом)
  • Создание собственных случайных распределений, подобных C ++ 11

Мне нужна униформа, нормальная, ядовитая и Рэлей.


person Arno Duvenhage    schedule 20.01.2016    source источник
comment
Нужна ли вам библиотека boost random number?   -  person shuttle87    schedule 20.01.2016
comment
@ Shuttle87, я медленно избавляюсь от всех ускорений из своей кодовой базы, так что я не очень хочу снова возвращать буст-библиотеки.   -  person Arno Duvenhage    schedule 20.01.2016
comment
О, я полностью понимаю, что не хочу зависимости от ускорения из-за размера этой зависимости. Однако большая часть веса буст-библиотек связана с кроссплатформенностью, что полезно в том случае, о котором вы спрашиваете. Если есть библиотека меньшего размера, содержащая только функции случайных чисел, я также хотел бы знать об этом.   -  person shuttle87    schedule 20.01.2016
comment
@ Shuttle87 гарантирует ли boost.random одинаковые результаты на разных платформах?   -  person Arno Duvenhage    schedule 20.01.2016
comment
Как насчет поиска дистрибутива / реализации с открытым исходным кодом и клонирования его как части вашей собственной кодовой базы / базы данных? Затем вы можете контролировать результаты для любой из ваших сред.   -  person ChrisR    schedule 20.01.2016
comment
Текущий подход: разработать собственные случайные распределения, соответствующие шаблонам C ++ 11 ... пока что требуется на удивление мало кода.   -  person Arno Duvenhage    schedule 21.01.2016
comment
@ArnoDuvenhage: имейте в виду, что шаблоны C ++ 11 на самом деле являются шаблонами, предоставляемыми вашим компилятором. Они защищены авторским правом! Обычно это не проблема, потому что вы можете использовать стандартную библиотеку с подходящим компилятором. Однако вы не можете просто использовать дистрибутив GCC с MSVC или наоборот.   -  person MSalters    schedule 21.01.2016
comment
@MSalters: Я посмотрел код libstdc ++, но еще не прошел лицензию - думал, что это открытый исходный код. Спасибо   -  person Arno Duvenhage    schedule 22.01.2016
comment
@Arno: Это открытый исходный код. Открытый исходный код означает, что он защищен авторским правом, но если вы соблюдаете соответствующие условия лицензии с открытым исходным кодом, вам разрешается копировать код. Т.е. читайте лицензию.   -  person MSalters    schedule 22.01.2016
comment
Наткнулся на это: johndcook.com/blog/cpp_random_number_generation Кажется очень полным, но я буду придется адаптировать дистрибутивы для работы с движками C ++ 11.   -  person Arno Duvenhage    schedule 22.01.2016


Ответы (1)


Я создал свои собственные дистрибутивы C ++ 11:

template <typename T>
class UniformRealDistribution
{
 public:
    typedef T result_type;

 public:
    UniformRealDistribution(T _a = 0.0, T _b = 1.0)
        :m_a(_a),
         m_b(_b)
    {}

    void reset() {}

    template <class Generator>
    T operator()(Generator &_g)
    {
        double dScale = (m_b - m_a) / ((T)(_g.max() - _g.min()) + (T)1); 
        return (_g() - _g.min()) * dScale  + m_a;
    }

    T a() const {return m_a;}
    T b() const {return m_b;}

 protected:
    T       m_a;
    T       m_b;
};

template <typename T>
class NormalDistribution
{
 public:
    typedef T result_type;

 public:
    NormalDistribution(T _mean = 0.0, T _stddev = 1.0)
        :m_mean(_mean),
         m_stddev(_stddev)
    {}

    void reset()
    {
        m_distU1.reset();
    }

    template <class Generator>
    T operator()(Generator &_g)
    {
        // Use Box-Muller algorithm
        const double pi = 3.14159265358979323846264338327950288419716939937511;
        double u1 = m_distU1(_g);
        double u2 = m_distU1(_g);
        double r = sqrt(-2.0 * log(u1));
        return m_mean + m_stddev * r * sin(2.0 * pi * u2);
    }

    T mean() const {return m_mean;}
    T stddev() const {return m_stddev;}

protected:
    T                           m_mean;
    T                           m_stddev;
    UniformRealDistribution<T>  m_distU1;
};

Равномерное распределение дает хорошие результаты, а нормальное распределение дает очень хорошие результаты:

100000 значений -> 68,159% в пределах 1 сигмы; 95,437% в пределах 2 сигм; 99,747% в пределах 3 сигм

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

Как равномерный, так и нормальный дистрибутивы должны работать с любым движком C ++ 11 (протестирован с помощью std :: mt19937), а обеспечивает одинаковую последовательность на всех платформах, что именно то, что я хотел.

person Arno Duvenhage    schedule 23.01.2016
comment
Это только для чисел с плавающей запятой? Я пробую это в своем проекте, где я дал диапазон в целых числах, и я получаю исключение с плавающей запятой - person thomthom; 28.09.2020
comment
Использовал его только для чисел с плавающей запятой, но я не понимаю, почему вы получите исключение. - person Arno Duvenhage; 30.09.2020
comment
Если задано целое число, вы получите исключение деление на ноль. - person thomthom; 30.09.2020
comment
Да, нормальное распределение основывается на реальном равномерном распределении внизу. См. stackoverflow.com/questions/22016007/ - person Arno Duvenhage; 01.10.2020