и не случайно - альтернативы? - PullRequest
0 голосов
/ 17 октября 2011

Я возился с массивами, заполнял псевдослучайными числами, находил минимальные и максимальные значения, их индексы и количество вхождений, и заметил кое-что странное - при использовании 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";  
}

Ответы [ 6 ]

3 голосов
/ 17 октября 2011

Для начала, они на самом деле псевдо случайные числа, а не случайные числа.В любом случае, может случиться так, что действительно случайная последовательность имеет именно то свойство, которое вы видите :-) Последовательность 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
1 голос
/ 17 октября 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

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

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

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

0 голосов
/ 17 октября 2011

Поведение вашего генератора псевдослучайных чисел (PRNG) совершенно нормально.

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

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

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

0 голосов
/ 17 октября 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 должно быть наибольшим числом в самых больших количествах.
0 голосов
/ 17 октября 2011

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

0 голосов
/ 17 октября 2011

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

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

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


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

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

Примечательноне пиши rand() % 3000.Напишите

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

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

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

...