нисколько не случайно - альтернативы?

Я играл с массивами, заполняя псевдослучайными числами, находя минимальные и максимальные значения, их индексы и количество вхождений, и я заметил кое-что странное - при использовании srand, засеянного со временем, количество вхождений минимального и максимального значений ВСЕГДА равно. Мне это не кажется случайным.

Есть ли альтернативный способ получить РАЗНОЕ количество вхождений минимального и максимального значений, как можно было бы ожидать от случайных чисел?

Вот мой код (я учусь, поэтому он может быть беспорядочным и неэффективным, рекомендации приветствуются)

#include <cstdlib>
#include <iostream>
#include <time.h>

using namespace std;

void findExtremes( const int[], int); 

int main()
{
    const int lenght = 2000; //define lenght

    int array1[lenght];

    srand(time(0)); 

    for ( int i = 0; i < lenght; i++) //populate array with random numbers and print them out
    {
        array1[i] = rand() % 3000;
        cout << "Index " << i << " = " << array1[i] << endl;
    }

    findExtremes(array1, lenght);   // call fn

    return 0;
}

void findExtremes( const int array[], int size)
{
     int maxV, minV, maxI, minI;
     maxV = array[0];
     minV = array[0];
     minI = 0;
     maxI = 0;

     for ( int i = 1; i < size; i++)
     {
         if ( array[i] > maxV)
            {
                maxV = array[i];
                maxI = i;
            }
         if ( array[i] < minV)
            {
                minV = array[i];
                minI = i;
            }
     }

     //find the number of occurances for min and max values

     int minOcc = 0;
     int maxOcc = 0;

     for ( int i = 1; i < size; i++)
     {
             if (array[i] == minV)
                 minOcc++;
             if (array[i] == minV)
                 maxOcc++;
     }

     //output

     cout << "\nMinmim value is index " << minI << " with value " << minV << " and " << minOcc << " occurances" << endl;
     cout << "\nMaxium value is index " << maxI << " with value " << maxV << " and " << maxOcc << " occurances" << endl << "\n";  
}

person dtech    schedule 17.10.2011    source источник
comment
rand () основан на псевдослучайной функции. Так что есть большая вероятность, что это не будет случайным. Если вам нужны сильные случайные значения, вам нужно искать криптографический генератор случайных чисел, так как большинство алгоритмов шифрования основано на действительно сильном генераторе.   -  person crazyjul    schedule 17.10.2011
comment
вы сравниваете два раза с minV (при нахождении вхождений)   -  person DeyyyFF    schedule 17.10.2011
comment
Спасибо, DeyyyFF, я полностью себя обманул. Пожалуйста, закройте вопрос. Я чувствую себя глупо и стыдно :) Ленивое копирование и вставка явно плохая практика ...   -  person dtech    schedule 17.10.2011
comment
Не думаю, что вопрос следует закрывать. Большинство ответов просто неверны в отношении генерации случайных чисел и заполнения. Вопрос все еще имеет свою ценность, потому что многие люди попали в одну и ту же ловушку.   -  person dmeister    schedule 17.10.2011


Ответы (6)


Для начала, это на самом деле псевдо случайные числа, а не случайные числа. В любом случае может случиться так, что действительно случайная последовательность имеет именно то свойство, которое вы видите :-) Последовательность 1,1,1,1,1 с такой же вероятностью встречается в действительно случайном наборе, как и 5,2,4,2,99.

Если вам нужна «более случайная» случайная последовательность, я бы не стал использовать обычные, поставляемые с библиотеками C (если только эти библиотеки не были написаны людьми, которые понимают случайность) - вам следует изучить такие вещи, как Mersenne Twister, используя /dev/random ( если под Linux) и так далее.

Вы также можете посмотреть этот фрагмент кода.

if (array[i] == minV)
    minOcc++;
if (array[i] == minV)
    maxOcc++;

Я считаю, что последний if следует сравнивать с maxV, а не с minV. В противном случае вероятность того, что ваш минимальный и максимальный счет будет отличаться, равна нулю.

Когда я вношу это изменение (и меняю % 3000 на % 30, чтобы получить ряд дубликатов), я вижу:

Minmim value is index 112 with value 0 and 65 occurances
Maxium value is index 24 with value 29 and 58 occurances

И, не то чтобы это действительно важно с точки зрения этого вопроса, вы можете немного очистить свою орфографию:

  • lenght -> length.
  • minmum -> minimum
  • maxium -> maximum
  • occurances -> occurrences
person paxdiablo    schedule 17.10.2011
comment
Mersenne Twister имеет равномерное распределение, точно так же. У него действительно большее состояние, ведущее к более длительному периоду псевдослучайности. - person sehe; 17.10.2011
comment
Опять же, ленивое и поспешное копирование / вставка виновато, что касается орфографии, даже если я не носитель языка, я на самом деле знаю правильное написание этих слов, просто не особо обращал внимание на то, что я вставил - это даже не предполагалось, что его увидят другие, пока эта ленивая ошибка с пастой не привела меня сюда. Теперь все работает как надо, большое спасибо. - person dtech; 17.10.2011

Я выполняю численное моделирование по физике, и моя группа использует библиотеку GSL для этого:

#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

class Random
{
private:
    gsl_rng* r; //!< Pointer to the gsl rng
public:
    //! Constructor: uses argument as the seed
    Random(long unsigned int seed);

    long int R(int N);
    long double R();
    long double gaussianR(long double sigma);
};

inline Random::Random(long unsigned int s)
{
    r = gsl_rng_alloc( gsl_rng_taus );
    gsl_rng_set(r, s); //seed to use to the pseudo-aleatory number generator.
}

// a uniform number between 0 and N-1
inline long int Random::R(int N)
{
    return gsl_rng_uniform_int (r, N);
}

// a uniform number between 0 and 1
inline long double Random::R()
{
    return gsl_rng_uniform_pos( r );
}

// a gaussian distribution with sigma
inline long double Random::gaussianR(long double sigma)
{
    return gsl_ran_gaussian(r, sigma);
}

вы должны скомпилировать его с флагами: OTHER_LDFLAGS = -lgsl -lm -lgslcblas

и добавьте include и libs (это для случая установки fink):

HEADER_SEARCH_PATHS = / sw / include LIBRARY_SEARCH_PATHS = / sw / lib

Надеюсь это поможет.

person Jorge Leitao    schedule 17.10.2011

Вы можете использовать новую библиотеку random, включенную в C ++ 11, или библиотеку Boost :: Random, на которой она основана.

person Ayjay    schedule 17.10.2011

Генератор псевдослучайных чисел (ГПСЧ) работает нормально.

Фактически, если вы наберете достаточно чисел из rand(), вы всегда будете получать одни и те же экстремумы, поскольку они распределены равномерно.

В вашем случае возникает вопрос: нужно ли вам другое поведение? Вы не должны набрасываться на истинные случайные числа, как предлагает @sehe. Это может быть бесполезно и даже проблематично при работе со стохастическим моделированием, которым являются алгоритмы Монте-Карло. Представьте, что вы хотите отладить фрагмент кода на основе случайных чисел или ваш коллега намерен проверить ваши результаты: как бы вы поступили, если бы вы не смогли воспроизвести ту же случайную последовательность?

Это одна из причин, почему ГПСЧ достаточно и часто предпочтительнее, когда вам не нужны криптозащищенные случайные числа.

person jopasserat    schedule 17.10.2011

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

Minmim value is index 1194 with value 0 and 1 occurances
Maxium value is index 1264 with value 2995 and 1 occurances

Minmim value is index 1958 with value 1 and 1 occurances
Maxium value is index 1510 with value 2991 and 1 occurances

...

Однако в коде есть две ошибки:

  • Во втором цикле for вы должны начать с i = 0.
  • Вы должны сравнивать с maxV вместо minV в том же цикле.

Что касается генерации случайных чисел:

  • При заполнении одинаковым числом серия вызовов rand () должна возвращать те же числа. rand () предназначен не для случайных чисел, а для псевдослучайных чисел. rand () должен быть таким, потому что, например, симуляция выдаст те же результаты при запуске с одним и тем же семенем. Это очень красивый отель.
  • Вы заполняете его текущим временем, что нормально, и поэтому rand () должен каждый раз возвращать разные серии чисел (по крайней мере, если не вызывается несколько раз в секунду) . Посев мне нравится. Фактически это очень похоже на пример, приведенный здесь.
  • Размер выборки - 2000, а диапазон генерируемых чисел - 3000. Это означает, что маловероятно, чтобы минимальный и максимальный размер всегда были одинаковыми. Если размер выборки составляет миллион, с высокой вероятностью 2999 должно быть наибольшим числом в большинстве прогонов.
person dmeister    schedule 17.10.2011

Господа: ПРИМЕЧАНИЕ

Да! Это старый ответ. А в эпоху c ++ 11 непременно используйте c ++ 11 <random>. Но пожалуйста не голосуйте против этого вопроса спустя годы после того, как вы думаете, Фу Все знают rand() зло !. На самом деле это не так. Он просто ограничен, и его очень легко использовать ненадлежащим образом. Но - как исторический факт, он существует как API, и по-прежнему полезно задокументировать, как его можно лучше использовать. Я не удаляю этот ответ по одной причине.

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


Пожалуйста прочти

http://eternalconfuzzled.com/arts/jsw_art_rand.aspx

В частности, не пишите rand() % 3000. Писать

 int r = rand() / ( RAND_MAX / 3000 + 1 );

Фактически, random должен быть равномерно распределен, а это означает, что на самом деле нижняя и верхняя границы будут иметь почти 100% вероятность появления, когда количество выборок достаточно велико (для начала, больше, чем размер домена).

Вот что такое true random (попробуйте реализовать алгоритм Монте-Карло без него - вы будете очень недовольны)

person sehe    schedule 17.10.2011
comment
Людям, которые ищут более свежие советы, предлагается ознакомиться с случайный (... ☺) выбор других моих ответов с участием random в c ++ - person sehe; 09.04.2014