На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Генерация случайных чисел по нормальному закону распределения
    Как в C++ сгенерировать случайные числа по нормальному закону распределения?
    Есть ли какие-нибудь библиотечные функции для генерирования случайных чисел по нормальному закону распределения?
    Если нет таких библиотечных функций, то как это сделать?
        std::normal_distribution, определён в <random>. Использовать нужно как-то так:
        ExpandedWrap disabled
          std::random_device              source;               // генератор целых (аналог srand())
          std::mt19937                    gen(source());        // алгоритм для псевдослучайных на основе простых чисел Мерсенна
          std::normal_distribution<float> nd(100.f, 10.f);      // нормальное распределение с медианой и дисперсией, равными 100
           
          /* ... */
           
          float x = nd(gen());  // очередное нормально распределённое
        В <random> много интересного есть.
          Обращаю внимание, что любимая Windows (даже Win 10) осталась в плане датчика генерации случайных чисел на уровне начала 1990-х годов.
          Здесь RAND_MAX = 32767 = 2**15-1. Между тем, как в любой нормальной ОС RAND_MAX = 2**31-1.
          Поэтому лично я использую ниже приведенный комплект программ для равномерной (не нормальной!) генерации случайных чисел.
          Обратите на это внимание, если не устроит работа датчика нормально распределенных чисел.
          ExpandedWrap disabled
            //---------------------------------------------------------------------------
             
            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;
            }
            //---------------------------------------------------------------------------
          Сообщение отредактировано: mkudritsky -
            Windows-то тут причём? Это RTL какой-то, не указано, какой, реализации языка C. Так-то у нас ещё с C++11 есть <random>
              Цитата 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 таких функций нет?
              Сообщение отредактировано: mkudritsky -
                RAND_MAX определяется в заголовочных файлах библиотек C. Стандартом языка он не определяется как конкретное значение. Формально он должен соответствовать возможностям исполнительной платформы, однако MS, к примеру, славится большой тягой к сохранению обратной совместимости, и коли когда-то, ещё в бытность 16-битных платформ, он был по факту INT_MAX, с тех пор не менялся, чтобы ненароком не поломать старый код.
                Для C, честно говоря, не помню, как там с новыми Стандартами, я счас в 200 км от дома, так что раньше понедельника не скажу. А так да, в Стандарте C++ <random> уже давно, и там нет проблем с обратной совместимостью, это целиком новый интерфейс.
                  Цитата 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-битного датчика уже хватает на все мыслимые и немыслимые запросы.
                  Сообщение отредактировано: mkudritsky -
                    На все мыслимые запросы 31-разрядного случайного числа не хватает, но не из-за разрядности числа, а из-за короткого периода и недостаточного качества. Это, к примеру, задачи стохастического моделирования. Но обычно в таких случаях пользуются сторонними ГПСЧ, "вихрем Мерсенна", например. Существует и 64-разрядный вариант.

                    В MinGW, видимо, обеспечивают совместимость с компиляторами Microsoft.
                    В RTL Microsoft, возможно, есть и вариант ГПСЧ с long int выходом, надо посмотреть в заголовке.

                    В 64-разрядных OS Linux 64 разряда - это разрядность адреса, а не данных. Поэтому используется тот же ГПСЧ, что и в 32-разрядных ОС.
                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                    0 пользователей:


                    Рейтинг@Mail.ru
                    [ Script execution time: 0,0273 ]   [ 16 queries used ]   [ Generated: 24.04.24, 05:29 GMT ]