генерация случайного числа с нормальным распределением в определенном диапазоне (например, [0,1]) в программировании на языке C [дубликат]

Arrays.deepToString(arrayOfObject)

Выше функции печатает массив объектов разных примитивов.

[[AAAAA, BBBBB], [6, 12], [2003-04-01 00:00:00.0, 2003-10-01 00:00:00.0], [2003-09-30 00:00:00.0, 2004-03-31 00:00:00.0], [Interim, Interim], [2003-09-30, 2004-03-31]];
102
задан Joe Gauterin 12 October 2012 в 16:53
поделиться

17 ответов

Преобразование Box-Muller - это то, что обычно используется. Это правильно создает значения с нормальным распределением.

http://en.wikipedia.org/wiki/Normal_distribution#Generating_values_from_normal_distribution

http: //en.wikipedia.org/wiki/Box_Muller_transform

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

82
ответ дан yhw42 26 August 2018 в 12:19
поделиться

Компьютер является детерминированным устройством. В расчетах нет случайности. Кроме того, арифметическое устройство в ЦП может оценивать суммирование по некоторому конечному набору целых чисел (выполняя оценку в конечном поле) и конечный набор действительных рациональных чисел. А также выполняются побитовые операции. Math заключает сделку с более большими наборами, такими как [0.0, 1.0] с бесконечным числом точек.

Вы можете прослушивать какой-либо провод внутри компьютера с каким-то контроллером, но будут ли они иметь равномерные распределения? Я не знаю. Но если предположить, что это сигнал является результатом накопления значений огромного количества независимых случайных величин, тогда вы получите примерно нормальную распределенную случайную величину (это было доказано в теории вероятностей)

Существуют алгоритмы, называемые псевдореальными случайный генератор. Как я понял, целью псевдослучайного генератора является эмулирование случайности. И критерии доброты: - эмпирическое распределение сходится (в некотором смысле - точечно, равномерно, L2) к теоретическим - значения, которые вы получаете от случайного генератора, как представляется, идеальны. Конечно, это неправда с «реальной точки зрения», но мы предполагаем, что это правда.

Один из популярных методов - вы можете суммировать 12 irv с равномерными распределениями ... Но, честно говоря, при деривации Центральная предельная теорема с помо- щью преобразования Фурье, серия Тейлора, необходимо иметь n -> + inf предположения пару раз. Так, например, теоретико - Лично я не понимаю, как люди выполняют суммирование по 12 i.r.v. с равномерным распределением.

У меня была теория пробок в университете. И особенно для меня это просто математический вопрос. В университете я увидел следующую модель:


double generateUniform(double a, double b)
{
  return uniformGen.generateReal(a, b);
}

double generateRelei(double sigma)
{
  return sigma * sqrt(-2 * log(1.0 - uniformGen.generateReal(0.0, 1.0 -kEps)));
}
double generateNorm(double m, double sigma)
{
  double y2 = generateUniform(0.0, 2 * kPi);
  double y1 = generateRelei(1.0);
  double x1 = y1 * cos(y2);
  return sigma*x1 + m;
}

Такой способ, как сделать это, был просто примером, я предполагаю, что существуют другие способы его реализации.

Доказательство того, что это правильно, можно найти в этой книге «Москва, БМТУ, 2004: XVI Теория вероятностей, пример 6.12, с.246-247» из Крищенко Александр Петрович ISBN 5-7038-2485-0

К сожалению, я не знаю о существовании перевода этой книги на английский язык.

-3
ответ дан bruziuz 26 August 2018 в 12:19
поделиться

EDIT: С 12 августа 2011 года у нас есть C ++ 11 , который непосредственно предлагает std::normal_distribution , что я и хотел сегодня.

Вот оригинальный ответ:

Вот некоторые решения, упорядоченные по возрастающей сложности.

  1. Добавьте 12 равномерных числа от 0 до 1 и вычесть 6. Это будет соответствовать среднему и стандартным отклонениям нормальной переменной. Очевидным недостатком является то, что диапазон ограничен +/- 6 - в отличие от истинного нормального распределения.
  2. Преобразование Box-Muller - было перечислено выше и относительно просто реализовать. Если вам нужны очень точные образцы, имейте в виду, что преобразование Box-Muller в сочетании с некоторыми однородными генераторами страдает от аномалии под названием Neave Effect. HR Neave, «Об использовании преобразования Box-Muller с мультипликативными конгруэнтными генераторами псевдослучайных чисел», Applied Statistics, 22, 92-97, 1973
  3. . Для лучшей точности я предлагаю рисовать форму и применять обратное кумулятивное нормальное распределение для получения нормально распределенных вариаций. Вы можете найти очень хороший алгоритм для обратного кумулятивного нормального распределения в

https://web.archive.org/web/20151030215612/http://home.online. no / ~ pjacklam / notes / invnorm /

Надеюсь, что помогает

Peter

40
ответ дан Community 26 August 2018 в 12:19
поделиться

Список comp.lang.c FAQ разделяет три разных способа легко генерировать случайные числа с распределением Гаусса.

Вы можете взглянуть на это: http://c-faq.com/lib/gaussian.html

-1
ответ дан Delgan 26 August 2018 в 12:19
поделиться

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

4
ответ дан Denis Arnaud 26 August 2018 в 12:19
поделиться

Если вы используете C ++ 11, вы можете использовать std::normal_distribution :

#include <random>

std::default_random_engine generator;
std::normal_distribution<double> distribution(/*mean=*/0.0, /*stddev=*/1.0);

double randomNumber = distribution(generator);

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

3
ответ дан Drew Noakes 26 August 2018 в 12:19
поделиться

Взгляните на то, что я нашел.

Эта библиотека использует алгоритм Зиггурата.

-1
ответ дан dwbrito 26 August 2018 в 12:19
поделиться

Реализация Box-Muller:

#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
using namespace std;
 // return a uniformly distributed random number
double RandomGenerator()
{
  return ( (double)(rand()) + 1. )/( (double)(RAND_MAX) + 1. );
}
 // return a normally distributed random number
double normalRandom()
{
  double y1=RandomGenerator();
  double y2=RandomGenerator();
  return cos(2*3.14*y2)*sqrt(-2.*log(y1));
}

int main(){
double sigma = 82.;
double Mi = 40.;
  for(int i=0;i<100;i++){
double x = normalRandom()*sigma+Mi;
    cout << " x = " << x << endl;
  }
  return 0;
}
0
ответ дан Gall Anonim 26 August 2018 в 12:19
поделиться

Существуют различные алгоритмы для обратного кумулятивного нормального распределения. Самые популярные в количественном финансировании тестируются на http://chasethedevil.github.io/post/monte-carlo--inverse-cumulative-normal-distribution/

Кроме того, , он показывает недостаток Ziggurat, как подходы.

-1
ответ дан jherek 26 August 2018 в 12:19
поделиться

Используйте std::tr1::normal_distribution.

Пространство имен std :: tr1 не является частью boost. Это пространство имен, которое содержит дополнения библиотеки из Технического отчета C ++ 1 и доступно в современных компиляторах Microsoft и gcc независимо от boost.

12
ответ дан Joe Gauterin 26 August 2018 в 12:19
поделиться

Я создал проект с открытым исходным кодом C ++ для стандартного теста генерации случайных чисел .

Он сравнивает несколько алгоритмов, включая

  • Метод центральной предельной теоремы
  • Преобразование Box-Muller
  • Полярный метод Марсалья
  • Алгоритм Зиггурата
  • Метод выборки обратного преобразования.
  • cpp11random использует C ++ 11 std::normal_distribution с std::minstd_rand (это фактически преобразование Box-Muller в clang).

Результаты версии с одной точностью (float) на iMac Corei5-3330S@2.70GHz, clang 6.1, 64-bit:

normaldistf [/g1]

Для правильности программа проверяет среднее, стандартное отклонение, асимметрию и эксцесс образцов. Было обнаружено, что метод CLT путем суммирования 4, 8 или 16 равномерных чисел не обладает хорошим куртозом, как другие методы.

Алгоритм Зиггурата имеет лучшую производительность, чем другие. Тем не менее, он не подходит для параллелизма SIMD, поскольку для этого нужен поиск в таблице и ветви. Box-Muller с набором инструкций SSE2 / AVX выполняется намного быстрее (x1.79, x2.99), чем версия алгоритма зиггурата, отличная от SIMD.

Поэтому я предлагаю использовать Box-Muller для архитектуры с SIMD наборы команд, и в противном случае может быть ziggurat.


PS в тесте используется простейший LCG PRNG для генерации однородных распределенных случайных чисел. Поэтому может быть недостаточно для некоторых приложений. Но сравнение производительности должно быть справедливым, потому что во всех реализациях используется тот же PRNG, поэтому в основном тест проверяет производительность преобразования.

19
ответ дан Milo Yip 26 August 2018 в 12:19
поделиться

Я выполнил определение PDF, данное в http://www.mathworks.com/help/stats/normal-distribution.html , и придумал следующее:

const double DBL_EPS_COMP = 1 - DBL_EPSILON; // DBL_EPSILON is defined in <limits.h>.
inline double RandU() {
    return DBL_EPSILON + ((double) rand()/RAND_MAX);
}
inline double RandN2(double mu, double sigma) {
    return mu + (rand()%2 ? -1.0 : 1.0)*sigma*pow(-log(DBL_EPS_COMP*RandU()), 0.5);
}
inline double RandN() {
    return RandN2(0, 1.0);
}

Возможно, это не лучший подход, но это довольно просто.

3
ответ дан MJVC 26 August 2018 в 12:19
поделиться

Быстрый и простой метод состоит в том, чтобы просто суммировать количество равномерно распределенных случайных чисел и принимать их среднее значение. См. Центральную предельную теорему для полного объяснения, почему это работает.

26
ответ дан Paul R 26 August 2018 в 12:19
поделиться

Вот пример C ++, основанный на некоторых ссылках. Это быстро и грязно, вам лучше не изобретать и использовать библиотеку boost.

#include "math.h" // for RAND, and rand
double sampleNormal() {
    double u = ((double) rand() / (RAND_MAX)) * 2 - 1;
    double v = ((double) rand() / (RAND_MAX)) * 2 - 1;
    double r = u * u + v * v;
    if (r == 0 || r > 1) return sampleNormal();
    double c = sqrt(-2 * log(r) / r);
    return u * c;
}

Вы можете использовать график QQ для изучения результатов и посмотреть, насколько он приближается к реальному нормальному распределению (ранжируйте ваши образцы 1..x, превратите ряды в пропорции общего количества х, т. е. сколько образцов, получите значения z и запишите их. Прямая линия вверх - это желаемый результат).

13
ответ дан Pete855217 26 August 2018 в 12:19
поделиться

Вот как вы создаете образцы на современном компиляторе C ++.

#include <random>
...
std::mt19937 generator;
double mean = 0.0;
double stddev  = 1.0;
std::normal_distribution<double> normal(mean, stddev);
cerr << "Normal: " << normal(generator) << endl;
11
ответ дан Petter 26 August 2018 в 12:19
поделиться

1) Графически интуитивно понятный способ генерации гауссовских случайных чисел заключается в использовании чего-то похожего на метод Монте-Карло. Вы создадите случайную точку в поле вокруг кривой Гаусса, используя ваш генератор псевдослучайных чисел в C. Вы можете вычислить, находится ли эта точка внутри или под распределением Гаусса, используя уравнение распределения. Если эта точка находится внутри гауссовского распределения, то вы получили свое гауссовское случайное число как значение x точки.

Этот метод не идеален, потому что технически гауссова кривая переходит к бесконечности, и вы не можете создать поле, которое приближается к бесконечности в измерении x. Но кривая Гуасса приближается к 0 в y-измерении довольно быстро, поэтому я бы не стал беспокоиться об этом. Ограничение размера ваших переменных в C может быть более ограничивающим фактором для вашей точности.

2) Другим способом было бы использовать Центральную предельную теорему, которая гласит, что при добавлении независимых случайных величин, они образуют нормальное распределение. Учитывая эту теорему, вы можете аппроксимировать гауссовское случайное число, добавив большое количество независимых случайных величин.

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

0
ответ дан Shubham 26 August 2018 в 12:19
поделиться

Посмотрите: http://www.cplusplus.com/reference/random/normal_distribution/ . Это самый простой способ получения нормальных распределений.

4
ответ дан telcom 26 August 2018 в 12:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: