Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[13.58.82.79] |
|
Сообщ.
#1
,
|
|
|
Как в C++ сгенерировать случайные числа по нормальному закону распределения?
Есть ли какие-нибудь библиотечные функции для генерирования случайных чисел по нормальному закону распределения? Если нет таких библиотечных функций, то как это сделать? |
Сообщ.
#3
,
|
|
|
std::normal_distribution, определён в <random>. Использовать нужно как-то так:
std::random_device source; // генератор целых (аналог srand()) std::mt19937 gen(source()); // алгоритм для псевдослучайных на основе простых чисел Мерсенна std::normal_distribution<float> nd(100.f, 10.f); // нормальное распределение с медианой и дисперсией, равными 100 /* ... */ float x = nd(gen()); // очередное нормально распределённое |
Сообщ.
#4
,
|
|
|
Обращаю внимание, что любимая Windows (даже Win 10) осталась в плане датчика генерации случайных чисел на уровне начала 1990-х годов.
Здесь RAND_MAX = 32767 = 2**15-1. Между тем, как в любой нормальной ОС RAND_MAX = 2**31-1. Поэтому лично я использую ниже приведенный комплект программ для равномерной (не нормальной!) генерации случайных чисел. Обратите на это внимание, если не устроит работа датчика нормально распределенных чисел. //--------------------------------------------------------------------------- int iRand() { // Аналог rand() для юродиевых версий "любимой" Windows, где RAND_MAX=32767 int iR=rand(); if ( RAND_MAX == 32767 ) { // 32767=2**15-1 iR <<= 15; // iR = iR*32768 (32768=2**15) int iL = rand(); iR |= iL; // iR = rand()*(2**15)+rand; } return iR; } //--------------------------------------------------------------------------- int iRandom(int iMin, int iMax) { // Возвращает случайное целое число между iMin и iMax. Границы могут генерироваться if (iMin < iMax) return iMin + iRand() % (iMax - iMin + 1); else if ( iMin == iMax ) return iMin; else return iMin - 1; // Если границы заданы неверно, то возвращается такое число } //--------------------------------------------------------------------------- double dbRandom(double dbMin, double dbMax) { // Возвращает случайное вещественное число между dbMin и dbMax. Границы могут генерироваться if (dbMin < dbMax) { if (RAND_MAX == 32767) return dbMin + ((dbMax - dbMin) * (double)iRand()) / 1073741823.0; // = double(2**30-1) else return dbMin + ((dbMax - dbMin) * (double)iRand()) / (double)RAND_MAX; } else if (dbMin == dbMax) return dbMin; else return dbMin - 1.0; } //--------------------------------------------------------------------------- |
Сообщ.
#5
,
|
|
|
Windows-то тут причём? Это RTL какой-то, не указано, какой, реализации языка C. Так-то у нас ещё с C++11 есть <random>
|
Сообщ.
#6
,
|
|
|
Цитата Qraizer @ Это RTL какой-то, не указано, какой, реализации языка C Да, виноват. Указываю версии: 1). Linux Debian 9.13 32bit/64bit LXDE clang version 3.8.1-24 gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1) Везде RAND_MAX=2**31-1=2147483647 P.S. Это еще проверял на клоне Ubuntu: Runtu 14.01.1 LITE в 2014 году. 2). Windows 7 32bit/64bit SP1 со всеми обновлениями до 14.01.2020. Qt 5.5.0 mingw492_32 и другой компилятор gcc version 9.2.0 (tdm64-1) Везде RAND_MAX=2**15-1=32767 P.S. Тоже самое на Win 10 Home 64bit. Хотелось бы узнать, в чем проблема. Грешил на Windows, видимо по моей ошибке. (Где-то услышал мнение, что RAND_MAX прописана в API Windows). Для моих задач важен качественный датчик псевдослучайных чисел, а не оперирующий только цифрами 0, 1,..., 32767. А класс <random> только под C++? Под обычный ansi C таких функций нет? |
Сообщ.
#7
,
|
|
|
RAND_MAX определяется в заголовочных файлах библиотек C. Стандартом языка он не определяется как конкретное значение. Формально он должен соответствовать возможностям исполнительной платформы, однако MS, к примеру, славится большой тягой к сохранению обратной совместимости, и коли когда-то, ещё в бытность 16-битных платформ, он был по факту INT_MAX, с тех пор не менялся, чтобы ненароком не поломать старый код.
Для C, честно говоря, не помню, как там с новыми Стандартами, я счас в 200 км от дома, так что раньше понедельника не скажу. А так да, в Стандарте C++ <random> уже давно, и там нет проблем с обратной совместимостью, это целиком новый интерфейс. |
Сообщ.
#8
,
|
|
|
Цитата Qraizer @ MS, к примеру, славится большой тягой к сохранению обратной совместимости Думаю, что это самое правильное предположение! Тем не менее, наверное, вопрос был поднят не зря. Если кто-то будет создавать датчики псевдослучайных чисел на базе классической функции rand(), то должен отдавать себе отчет: в Windows этот датчик "16-битный" и для генерации чисел используются 15 бит (RAND_MAX=2**15-1). В свое время меня, например, такая частота (0..32767) генерации псевдослучайных чисел для решения задачи не устроила - было невооруженным глазом видно, что последовательность чисел редкая. (Кстати, я очень долго искал причину этого явления! Кучу времени потерял, пока понял что к чему). Так что есть два выхода из положения в OS Windows: 1. Использовать C++ и класс <random>. 2. При помощи приведенных мною выше программ (или аналогов) генерировать псевдослучайные числа в два обращения к функции rand() - получится 30-битный датчик псевдослучайных чисел. В OS Linux классический датчик псевдослучайных числел 31-битный (RAND_MAX=2**31-1). Кстати, если не устраивает и 30/31-битный датчик, то по аналогии с приведенными выше программами можно организовать 60/62-битные датчики соответственно с RAND_MAX=2**60-1(2**62-1). Разумеется, работать надо с 64-битным целым типом данных long long int. В OS Windows будет 4-кратное обращения к функции rand(), а в Linux - 2-кратное. P.S. Был немного удивлен, что в 64-разрядных ОС Linux датчик rand() по-прежнему 31-битный, а не 63-битный. Наверное, не смогли найти достаточно большое простое число для этой цели. А может 31-битного датчика уже хватает на все мыслимые и немыслимые запросы. |
Сообщ.
#9
,
|
|
|
На все мыслимые запросы 31-разрядного случайного числа не хватает, но не из-за разрядности числа, а из-за короткого периода и недостаточного качества. Это, к примеру, задачи стохастического моделирования. Но обычно в таких случаях пользуются сторонними ГПСЧ, "вихрем Мерсенна", например. Существует и 64-разрядный вариант.
В MinGW, видимо, обеспечивают совместимость с компиляторами Microsoft. В RTL Microsoft, возможно, есть и вариант ГПСЧ с long int выходом, надо посмотреть в заголовке. В 64-разрядных OS Linux 64 разряда - это разрядность адреса, а не данных. Поэтому используется тот же ГПСЧ, что и в 32-разрядных ОС. |