Генерация случайных чисел в C - PullRequest
12 голосов
/ 18 июня 2010

При поиске Учебников по генерации случайных чисел в КИ найдено эта тема

Когда я пытаюсь использовать функцию rand() без параметров, я всегда получаю 0. Когда я пытаюсьиспользуя функцию rand() с параметрами, я всегда получаю значение 41. И всякий раз, когда я пытаюсь использовать функции arc4random() и random(), я получаю ошибку LNK2019.

Вот что я сделал:

#include <stdlib.h>
int main()
{
  int x;
  x = rand(6);
  printf("%d", x);
}

Этот код всегда генерирует 41. Где я иду не так?Я использую Windows XP SP3 и использую командную строку VS2010 в качестве компилятора.

Ответы [ 7 ]

31 голосов
/ 18 июня 2010

Вы должны вызвать srand () перед вызовом rand для инициализации генератора случайных чисел.

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

#include <stdlib.h>

int main ()
{
  srand ( 123 );
  int random_number = rand();
  return 0;
}

или вызовите его с изменяющимися источниками, то есть функцией времени

#include <stdlib.h>
#include <time.h>

int main ()
{
  srand ( time(NULL) );
  int random_number = rand();
  return 0;
}

В ответ на комментарий Луны rand () генерирует случайное число с равной вероятностью от 0 до RAND_MAX(макрос, предопределенный в stdlib.h)

Затем вы можете сопоставить это значение с меньшим диапазоном, например

int random_value = rand(); //between 0 and RAND_MAX

//you can mod the result
int N = 33;
int rand_capped = random_value % N;  //between 0 and 32
int S = 50;
int rand_range = rand_capped + S; //between 50 and 82

//you can convert it to a float
float unit_random = random_value / (float) RAND_MAX; //between 0 and 1 (floating point)

Это может быть достаточно для большинства применений, но его стоит указатьиз того, что в первом случае использование оператора mod вносит небольшое смещение, если N не делится равномерно на RAND_MAX + 1.

Генераторы случайных чисел интересны и сложны, широко распространено мнение, что генератор rand () встандартная библиотека C не является генератором случайных чисел отличного качества, читайте (http://en.wikipedia.org/wiki/Random_number_generation для определения качества).

http://en.wikipedia.org/wiki/Mersenne_twister (источник http://www.math.sci.hiroshima -u.ac.jp / ~ m-mat / MT / emt.html ) - это популярный высококачественный генератор случайных чисел.

Кроме того, я не знаю ни arc4rand (), ни random (), поэтому не могу комментировать.

5 голосов
/ 18 июня 2010

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

Простое, но низкое качество семя - использовать текущее время:

srand(time(0));

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

Фон. Генераторы псевдослучайных чисел не создают последовательности истинных случайных чисел, а просто имитируют их. Учитывая номер начальной точки, PRNG всегда будет возвращать одну и ту же последовательность чисел. По умолчанию они начинаются с одного и того же внутреннего состояния, поэтому возвращают одинаковую последовательность.

Чтобы не получить ту же последовательность, вы меняете внутреннее состояние. Акт изменения внутреннего состояния называется «посев».

3 голосов
/ 21 июня 2010

Кроме того, линейные конгруэнтные PRNG имеют тенденцию производить больше случайности на старших битах, чем на младших битах, поэтому для ограничения результата не используйте модуль по модулю, а вместо этого используйте что-то вроде:

j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));

(Это из "Численных рецептов в Си", гл.7)

3 голосов
/ 20 июня 2010
#include <stdlib.h>

int main()
{
    int x;
    x = rand(6);
    printf("%d", x);
}

Особенно для новичка вы должны попросить ваш компилятор напечатать каждое предупреждение о плохом коде, который он может сгенерировать.Современные компиляторы знают много разных предупреждений, которые помогут вам лучше программировать.Например, когда вы компилируете эту программу с помощью компилятора GNU C:

$ gcc -W -Wall rand.c
rand.c: In function `main':
rand.c:5: error: too many arguments to function `rand'
rand.c:6: warning: implicit declaration of function `printf'

Здесь вы получаете два предупреждения.Первый говорит, что функция rand принимает только нулевые аргументы, а не один, как вы пытались.Чтобы получить случайное число от 0 до n, вы можете использовать выражение rand() % n, которое не идеально, но подходит для небольших n.Результирующие случайные числа обычно распределяются неравномерно;меньшие значения возвращаются чаще.

Второе предупреждение говорит вам, что вы вызываете функцию, которую компилятор не знает в этот момент.Вы должны сказать компилятору, сказав #include <stdio.h>.Какие включаемые файлы необходимы, для которых функции не всегда просты, но запрос спецификации Open Group для переносимых операционных систем работает во многих случаях: http://www.google.com/search?q=opengroup+rand.

Эти два предупреждения многое рассказывают об истории программирования на Cязык.40 лет назад определение функции не включало в себя количество параметров или типы параметров.Также было нормально вызывать неизвестную функцию, которая в большинстве случаев работала.Если вы хотите писать код сегодня, вам не следует полагаться на эти старые функции, а вместо этого включать предупреждения вашего компилятора, понимать предупреждения и затем исправлять их правильно.

1 голос
/ 16 февраля 2014
int *generate_randomnumbers(int start, int end){
    int *res = malloc(sizeof(int)*(end-start));
    srand(time(NULL));
    for (int i= 0; i < (end -start)+1; i++){
        int r = rand()%end + start;
        int dup = 0;
        for (int j = 0; j < (end -start)+1; j++){
            if (res[j] == r){
                i--;
                dup = 1;
                break;
            }
        }
        if (!dup)
            res[i] = r;
    }
    return res;
}
1 голос
/ 16 февраля 2011

Или, например, чтобы получить псевдослучайное int в диапазоне от 0 до 19, вы можете использовать старшие биты, например:

j = ((rand() >> 15) % 20;
1 голос
/ 18 июня 2010

Сначала вам нужно засечь генератор, потому что он не генерирует действительные случайные числа!

Попробуйте это:

#include <stdlib.h>
#include <time.h>
int main()
{
    // random seed, time!
    srand( time(NULL) ); // hackish but gets the job done.
    int x;
    x = rand(); // everytime it is different because the seed is different.
    printf("%d", x);
}
...