Форум программистов, компьютерный форум CyberForum.ru

Генератор нормально распределенной случайной величины в заданном диапазоне - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 80, средняя оценка - 4.70
NikWhite
1 / 1 / 0
Регистрация: 02.04.2013
Сообщений: 40
14.05.2013, 23:05     Генератор нормально распределенной случайной величины в заданном диапазоне #1
Здравствуйте, некоторое время назад я создавал тему с вопросом о том как сгенерировать случайные числа в диапазоне от Ν до M, Z число раз. Тогда мне посоветовали следующий код

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
double dblRand(double min, double max) {
 
    double x=(double)rand()/RAND_MAX;
    return min+x*(max-min);
 
}
 
// ---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender) {
 
    ListBox1->Clear();
    randomize();
 
    int lim = 100000; // число можно и поскромнее поставить, либо использовать для 
                      // вывода массива нечто другое :)
 
    while (lim--)
        ListBox1->Items->Add(FloatToStr(dblRand(140, 160)));
 
}
Но в последствии я понял, что генерируется не нормально распределенная величина (также называемое распределением Гаусса), а равномерно распределенная величина (а может я ошибаюсь???). Подскажите генератор случайной величины которая распределена нормально (по Гауссу), и так чтобы генерировались случайные числа в диапазоне от Ν до M, Z число раз.

Добавлено через 23 часа 55 минут
Подскажите пожалуйста, срочно нужно.. совсем застопорился.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.05.2013, 23:05     Генератор нормально распределенной случайной величины в заданном диапазоне
Посмотрите здесь:

Случайные числа в заданном диапазоне C++
C++ простые числа в заданном диапазоне
простое число в заданном диапазоне C++
C++ Вычислить математическое ожидание, дисперсию и среднеквадратичное отклонение случайной величины
Моделирование случайной величины с заданным законом распределения C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Ternsip
 Аватар для Ternsip
660 / 188 / 6
Регистрация: 10.05.2012
Сообщений: 595
15.05.2013, 15:11     Генератор нормально распределенной случайной величины в заданном диапазоне #2
NikWhite,
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
 
using namespace std;
 
double gen(double mn, double mx) { // не используйте min max это функции из cmath
    int dx = mx - mn;
    double accur = 1e3;
    int fmx = dx * accur;
    double t = rand()%fmx;
    t /= accur;
    return mn + t;
}
 
int main() {
    for (int i = 0; i < 1000; i++) {
        printf("%.5lf\n", gen(39, 42));
    }
    return 0;
}
Добавлено через 1 минуту
NikWhite, ваще тут при больших значениях фигня будет

Добавлено через 1 минуту
NikWhite, если числа маленькие, то юзайте

Добавлено через 41 секунду
NikWhite, randMAX просто слишком маленький
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
15.05.2013, 15:18     Генератор нормально распределенной случайной величины в заданном диапазоне #3
NikWhite, для генерации нормально распределенных случайных величин используется преобразование Бокса-Мюллера. Гуглится легко, на все про все - три простенькие формулы.
kamre
126 / 130 / 4
Регистрация: 25.12.2011
Сообщений: 438
15.05.2013, 18:19     Генератор нормально распределенной случайной величины в заданном диапазоне #4
Цитата Сообщение от NikWhite Посмотреть сообщение
нормально распределенной случайной величины в заданном диапазоне
А что это за такое "нормальное распределение" на конечном отрезке?
NikWhite
1 / 1 / 0
Регистрация: 02.04.2013
Сообщений: 40
15.05.2013, 19:47  [ТС]     Генератор нормально распределенной случайной величины в заданном диапазоне #5
Цитата Сообщение от kamre Посмотреть сообщение
А что это за такое "нормальное распределение" на конечном отрезке?
Имеется, промежуток, например от 200 до 300, в этом промежутке нужно сгенерировать нормально распределенную случайную величину.
kamre
126 / 130 / 4
Регистрация: 25.12.2011
Сообщений: 438
15.05.2013, 20:41     Генератор нормально распределенной случайной величины в заданном диапазоне #6
Цитата Сообщение от NikWhite Посмотреть сообщение
в этом промежутке нужно сгенерировать нормально распределенную случайную величину
Почитайте про определение нормального распределения, там никаких промежутков нет, любое действительное значение может приниматься.
NikWhite
1 / 1 / 0
Регистрация: 02.04.2013
Сообщений: 40
15.05.2013, 23:41  [ТС]     Генератор нормально распределенной случайной величины в заданном диапазоне #7
Цитата Сообщение от 0x10 Посмотреть сообщение
NikWhite, для генерации нормально распределенных случайных величин используется преобразование Бокса-Мюллера. Гуглится легко, на все про все - три простенькие формулы.
Пробовал бокса-мюллера,но он жутко медленный (зависал даже на 10 значениях), совсем не подходит. решил использовать центральную предельную теорему

double NormalDistribution()
C++
1
2
3
4
5
6
7
{
    double S = 0.;    
    for (int i = 0; i < 12; ++i) 
        S += (double)rand() / RAND_MAX;
 
   return S - 6.;
}
Попытался сделать, чтобы это работало в конкретном диапазоне (от 200 до 300), но не получилось, попадаются числа выпадающие из этого диапазона.

Добавлено через 13 минут
Цитата Сообщение от kamre Посмотреть сообщение
Почитайте про определение нормального распределения, там никаких промежутков нет, любое действительное значение может приниматься.
Я могу генерировать случайною величину в заданном диапазоне, она получится равномерно распределенной на этом промежутке, а потом с помощью центральной предельной теоремы перейду к нормально распределенной.

И еще Χ принадлежит [-∞;+∞], теоретически есть промежутки.

Добавлено через 2 часа 30 минут
Цитата Сообщение от Ternsip Посмотреть сообщение
NikWhite,
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
 
using namespace std;
 
double gen(double mn, double mx) { // не используйте min max это функции из cmath
    int dx = mx - mn;
    double accur = 1e3;
    int fmx = dx * accur;
    double t = rand()%fmx;
    t /= accur;
    return mn + t;
}
 
int main() {
    for (int i = 0; i < 1000; i++) {
        printf("%.5lf\n", gen(39, 42));
    }
    return 0;
}
Добавлено через 1 минуту
NikWhite, ваще тут при больших значениях фигня будет

Добавлено через 1 минуту
NikWhite, если числа маленькие, то юзайте

Добавлено через 41 секунду
NikWhite, randMAX просто слишком маленький
Тут не нормально распределенная получается и мне нужно генерировать от 1000 значений.
Psilon
Master of Orion
 Аватар для Psilon
5738 / 4686 / 619
Регистрация: 10.07.2011
Сообщений: 14,160
Записей в блоге: 5
Завершенные тесты: 4
15.05.2013, 23:44     Генератор нормально распределенной случайной величины в заданном диапазоне #8
Копипастю из старой своей методы:
Генерация нормально распределенных чисел. Неинтегрируемость функции нормального распределения не позволяет использовать приведенный метод. Поэтому для генерации нормально распределенных чисел применяется способ, основанный на центральной предельной теореме (ЦПТ). Согласно ЦПТ, распределение суммы независимых одинаково распределенных случайных величин с увеличением числа слагаемых стремится к нормальному распределению. Если слагаемые равномерно распределены в интервале [0,1], то
Генератор нормально распределенной случайной величины в заданном диапазоне
Сумма равномерных случайных величин сходится к нормальному распределению достаточно быстро, и практика показала, что уже при n > 10 сходимость хорошая.
Однако непосредственно пользоваться приведенными соотношениями нельзя из-за зависимости параметров распределения Y от числа слагаемых и жесткой связи между my и σ2y. Поэтому для нормальных случайных величин с заданными параметрами my и σy используется следующая двухэтапная процедура, основанная на устойчивости нормального распределения к линейному преобразованию.
В начале формируется последовательность чисел {z}, подчиненных нормированному нормальному распределению (т.е.нормальному распределению с параметрами mz = 0; σz=1). Для этого выполняется операция
Название: 2.JPG
Просмотров: 2996

Размер: 9.7 Кб
Как нетрудно видеть, mz = 0; σz=1.
Затем последовательность {z} преобразуется в требуемую последовательность
{y} по формуле
Название: 3.JPG
Просмотров: 2994

Размер: 9.4 Кб
Следует обратить внимание, что для получения одного числа последовательности {y} надо использовать 12 равномерных чисел.
Программа, реализующая описанную процедуру, в отличие от датчика равномерных чисел, может не содержаться в математическом обеспечении компьютера.
NikWhite
1 / 1 / 0
Регистрация: 02.04.2013
Сообщений: 40
16.05.2013, 19:31  [ТС]     Генератор нормально распределенной случайной величины в заданном диапазоне #9
Цитата Сообщение от Psilon Посмотреть сообщение
Копипастю из старой своей методы:
Ну код, наверное, так и выглядит
C++
1
2
3
4
5
6
7
{
    double S = 0.;    
    for (int i = 0; i < 12; ++i) 
        S += (double)rand() / RAND_MAX;
 
   return S - 6.;
}
Psilon
Master of Orion
 Аватар для Psilon
5738 / 4686 / 619
Регистрация: 10.07.2011
Сообщений: 14,160
Записей в блоге: 5
Завершенные тесты: 4
16.05.2013, 19:54     Генератор нормально распределенной случайной величины в заданном диапазоне #10
Ну а чего вам еще не хватает??
NikWhite
1 / 1 / 0
Регистрация: 02.04.2013
Сообщений: 40
16.05.2013, 22:49  [ТС]     Генератор нормально распределенной случайной величины в заданном диапазоне #11
Цитата Сообщение от Psilon Посмотреть сообщение
Ну а чего вам еще не хватает??
Дело то как раз и в промежутке, когда я генерирую равномерно распределенную случайную величину в промежутке от 200 и до 300, то все ок, но потом же эти значения используются в коде который я прислал, они складываются и в итоге распределение нормальное,а значения в этом промежутке не находятся (там получаются значения от 2х тысяч). Надо как то переписать код, чтобы значения были и нормально распределенные и находились в промежутке от 200 до 300.
Psilon
Master of Orion
 Аватар для Psilon
5738 / 4686 / 619
Регистрация: 10.07.2011
Сообщений: 14,160
Записей в блоге: 5
Завершенные тесты: 4
16.05.2013, 23:07     Генератор нормально распределенной случайной величины в заданном диапазоне #12
Еще раз:
http://www.cyberforum.ru/cgi-bin/latex.cgi?y =  {\sigma}_{y}z + {m}_{y}
NikWhite
1 / 1 / 0
Регистрация: 02.04.2013
Сообщений: 40
19.05.2013, 18:46  [ТС]     Генератор нормально распределенной случайной величины в заданном диапазоне #13
Цитата Сообщение от Psilon Посмотреть сообщение
Еще раз:
http://www.cyberforum.ru/cgi-bin/latex.cgi?y =  {\sigma}_{y}z + {m}_{y}
Так не работает.Видимо не совсем поняли. Мне нужно сделать так чтобы нормально распределенная случайная величина находилась в промежутке от 200 до 300, но так сделать нельзя, поэто нужно нгенерировать равномерную от 200 до 300, перевести ее в нормальную, и сделать проекцию, как буд то, нормально распределенная находится от 200 и до 300.
Psilon
Master of Orion
 Аватар для Psilon
5738 / 4686 / 619
Регистрация: 10.07.2011
Сообщений: 14,160
Записей в блоге: 5
Завершенные тесты: 4
19.05.2013, 19:04     Генератор нормально распределенной случайной величины в заданном диапазоне #14
NikWhite, омг, в вашем случае mx = 250, http://www.cyberforum.ru/cgi-bin/latex.cgi?\sigmax = 100/6 ~ 16.67
NikWhite
1 / 1 / 0
Регистрация: 02.04.2013
Сообщений: 40
19.05.2013, 23:42  [ТС]     Генератор нормально распределенной случайной величины в заданном диапазоне #15
Цитата Сообщение от Psilon Посмотреть сообщение
NikWhite, омг, в вашем случае mx = 250, http://www.cyberforum.ru/cgi-bin/latex.cgi?\sigmax = 100/6 ~ 16.67
250 получилась в результате (300+250)/2, а сигма -(300-200)/6 ? что за формула?что такое 6. Можете сказать в более общем виде, а то у меня границы любыми могут быть, не только 200 и 300.
Psilon
Master of Orion
 Аватар для Psilon
5738 / 4686 / 619
Регистрация: 10.07.2011
Сообщений: 14,160
Записей в блоге: 5
Завершенные тесты: 4
19.05.2013, 23:45     Генератор нормально распределенной случайной величины в заданном диапазоне #16
NikWhite, в общем виде
http://www.cyberforum.ru/cgi-bin/latex.cgi?{m}_{x} = \frac{a + b}{2}, http://www.cyberforum.ru/cgi-bin/latex.cgi?{\sigma }_{x} = \frac{b - a}{6}
6 - теорема чебышева и правило 3 сигм
NikWhite
1 / 1 / 0
Регистрация: 02.04.2013
Сообщений: 40
20.05.2013, 00:05  [ТС]     Генератор нормально распределенной случайной величины в заданном диапазоне #17
Цитата Сообщение от Psilon Посмотреть сообщение
NikWhite, в общем виде
http://www.cyberforum.ru/cgi-bin/latex.cgi?{m}_{x} = \frac{a + b}{2}, http://www.cyberforum.ru/cgi-bin/latex.cgi?{\sigma }_{x} = \frac{b - a}{6}
6 - теорема чебышева и правило 3 сигм
Спасибо большое, а у вас есть ссылка на теорию, где расписано более подробно как все это работает.
Psilon
Master of Orion
 Аватар для Psilon
5738 / 4686 / 619
Регистрация: 10.07.2011
Сообщений: 14,160
Записей в блоге: 5
Завершенные тесты: 4
20.05.2013, 00:12     Генератор нормально распределенной случайной величины в заданном диапазоне #18
NikWhite,
Генератор нормально распределенной случайной величины в заданном диапазоне
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4919 / 2662 / 243
Регистрация: 29.11.2010
Сообщений: 7,397
20.05.2013, 02:52     Генератор нормально распределенной случайной величины в заданном диапазоне #19
А если без извращений, то в бусте и С++11 есть удобные инструменты для генерации чисел в указанном диапазоне.
Распределение normal_distribution<double> name(нижняя граница, верхняя граница) совместно c Вихрем Мерсенна (mt19937) творят чудеса без всяких извратов
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.11.2013, 09:40     Генератор нормально распределенной случайной величины в заданном диапазоне
Еще ссылки по теме:

плотность вероятности случайной величины C++
Определить математическое ожидание дискретной случайной величины C++
Смоделировать алгоритм непрерывной случайной величины распределенной с плотностью C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
JleLLlka
0 / 0 / 0
Регистрация: 11.11.2013
Сообщений: 3
11.11.2013, 09:40     Генератор нормально распределенной случайной величины в заданном диапазоне #20
Цитата Сообщение от NikWhite Посмотреть сообщение
Подскажите генератор случайной величины которая распределена нормально (по Гауссу), и так чтобы генерировались случайные числа в диапазоне от Ν до M, Z число раз.
Не знаю снят ли до конца вопрос, но может кому пригодится. Так же прошу прощения за "много букв" но может кому будет интересно.

Тут нужно понимать что у нормального распределения есть такая характеристика как СКО(СреднеКвадратичное Отклонение) попробую объяснить на примере, что оно означает:
Например у нас есть выборка из 1000 значений (нормально распределенная) и например СКО (или сигма) = 30 означает, что 67% всех значений меньше либо равны 30.
Так же есть правило 2х сигм, говорящее о том что в диапазоне 2х сигм лежит 95% значений, и правило 3х сигм, говорящее о том, что 99,7% значений лежит в диапазоне 3х сигм.
Теперь на нашем примере:
67% (СКО, сигма) значений лежат в диапазоне от [-30, 30]
95% (2 сигма) значений лежат в диапазоне от [-60, 60] (30*2 = 60)
99,7% (3 сигма) значений лежат в диапазоне от [-90, 90] (30*3 = 90)

Теперь вернемся к твоей задаче, тебе нужны числа от M до N, не очень удачное обозначение, т.к. М обычно обозначается математическое ожидание(среднее значение), поэтому перефомулируем, так: нужны числа в диапазоне от N1 до N2, получаем:
M (мат. ожидание) = (N2+N1) / 2 (это просто среднее значение, от которого может колебатся ошибка)
3 сигма = M-N1, т.е. M-N1 это максимальное значение которое может принимать ошибка, и говоря о 3 сигма, мы говорим, что мы хотим такую выборку, 99,7% которой не больше M-N1
соответственно СКО (сигма) = 3 сигма / 3 = (M-N1)/3 это то значение с которым ты должен использовать генератор нормальных чисел, чтобы генерируемые значения не выходили из твоего диапазона.

Далее сам генератор:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
float gaussrand(float MO, float sko)
{
    float sum=0, x;
 
    for (int i=0;i<28;i++)
        sum+=1.0*rand()/RAND_MAX;
    x = (sqrt(2.0)*(sko)*(sum-14.))/2.11233 + MO;
 
    return x;
}
Цифра «28» и «2.11233» получены эмпирическим путем (читай методом научного тыка), значения были подобраны таким образом, что бы сигме соответствовало 67% значений, 2ум сигмам 95% значений, ну и 3м сигмам 99,7% значений (другие подобные функции редко проходят подобную проверку). Так же было проверено следующее: если сгенерировать 2е случайные, нормально распределенные величины и их сложить, то СКО этой величины должно быть равно qsrt(2)*сигма, моя функция проходит эту проверку.

Результат работы генератора:
Генерировалось 10.000.000 значений с СКО = 0.3, потом вычислялась статистика полученной выборки, результат:
67% = 0.299913049 | 95% = 0.600402057 | 99.7% = 0.900952756
67% = 0.300060332 | 95% = 0.600611031 | 99.7% = 0.901350796
67% = 0.299943686 | 95% = 0.600414336 | 99.7% = 0.900437713
67% = 0.300084651 | 95% = 0.60008353 | 99.7% = 0.901191831
67% = 0.299931049 | 95% = 0.599887371 | 99.7% = 0.90083015
67% = 0.299906909 | 95% = 0.600438833 | 99.7% = 0.901222467
67% = 0.300041765 | 95% = 0.600383639 | 99.7% = 0.900027037
67% = 0.300010741 | 95% = 0.60065949 | 99.7% = 0.900523663
67% = 0.299839497 | 95% = 0.600499749 | 99.7% = 0.900946617
67% = 0.300182939 | 95% = 0.600420237 | 99.7% = 0.901810706
Среднее СКО = 0.299977

Ошибка генератора 0.0077% ничтожно малое значение.

Ну и пример использования:
Например, функция для решения твоей задачи будет иметь следующий вид (сохраняя твои обозначения):

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Числа генерируются в диапазоне [N, M]
//Генерируется Z чисел
//Сгенерированные значения будут помещены в массив array
void gen_array( const double N, const double M, const int Z, double *array )
{
  double average = ( N + M ) / 2.;
  double sigma = ( average – N ) / 3.;
 
  for( int i=0; i<Z; i++ ) {
    double new_value = gaussrand( average, sigma );
 
    //есть вероятность (0.3%) что сгенерированное число выйдет за нужный нам диапазон
    while( new_value < N || new_value > M )
      new_value = gaussrand( average, sigma ); //если это произошло генерируем новое число.
 
    array[i] = new_value;
  }
}
Пример вызова:
C++ (Qt)
1
2
3
4
5
6
void main()
{
  double array[1000];
  gen_array( 50, 100, 1000, array );
  //будет сгенерировано 1000 значений в диапазоне [50, 100]
}
С уважением Алексей

Добавлено через 1 час 26 минут
Цитата Сообщение от JleLLlka Посмотреть сообщение
Цифра «28» и «2.11233» получены эмпирическим путем (читай методом научного тыка)
Не дают чето свое же сообщение поправить, сейчас ещё по эмпирировал
Лучше использовать числа 25 и 1.99661, т.е. функция примит вид:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
float MainWindow::gaussrand(float MO, float sko)
{
    float sum=0, x;
 
    for (int i=0;i<25;i++)
        sum+=1.0*rand()/RAND_MAX;
    x = (sqrt(2.0)*(sko)*(sum-12.5))/1.99661 + MO;
 
    return x;
}
Результат:
67% = 0.300074607 | 95% = 0.600425005 | 99.7% = 0.899374366
67% = 0.299821496 | 95% = 0.600100815 | 99.7% = 0.898648262
67% = 0.300249696 | 95% = 0.600120068 | 99.7% = 0.898583174
67% = 0.299997002 | 95% = 0.600055397 | 99.7% = 0.898914099
67% = 0.300120205 | 95% = 0.600100577 | 99.7% = 0.900645971
67% = 0.299815416 | 95% = 0.599782825 | 99.7% = 0.900483012
67% = 0.299841166 | 95% = 0.600009799 | 99.7% = 0.898874998
67% = 0.300061643 | 95% = 0.599899948 | 99.7% = 0.899212003
67% = 0.300081104 | 95% = 0.600217521 | 99.7% = 0.900146246
67% = 0.300067931 | 95% = 0.600314617 | 99.7% = 0.899646521
среднее ско: 0.300013
Yandex
Объявления
11.11.2013, 09:40     Генератор нормально распределенной случайной величины в заданном диапазоне
Ответ Создать тему
Опции темы

Текущее время: 11:06. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru