Генерирование случайных чисел в C
При поиске учебников по генерации случайных чисел в C я нашел этот раздел
Когда я пытаюсь использовать функцию 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 Командная строка как компилятор.
Ответы
Ответ 1
Вы должны вызвать 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(), поэтому я не могу комментировать.
Ответ 2
Вам нужно засеять PRNG, чтобы он начинался с другого значения каждый раз.
Простым, но низкокачественным семенем является использование текущего времени:
srand(time(0));
Это поможет вам начать, но считается низким качеством (например, не используйте это, если вы пытаетесь создать ключи RSA).
Фон. Генераторы псевдослучайных чисел не создают истинные последовательности случайных чисел, а просто имитируют их. Учитывая номер начальной точки, PRNG всегда будет возвращать одну и ту же последовательность чисел. По умолчанию они начинаются с одного и того же внутреннего состояния, поэтому возвращают ту же последовательность.
Чтобы не получить одну и ту же последовательность, вы меняете внутреннее состояние. Акт изменения внутреннего состояния называется "посев".
Ответ 3
#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 лет назад определение функции не включало количество параметров или типы параметров. Также было нормально называть неизвестную функцию, которая в большинстве случаев работала. Если вы хотите писать код сегодня, вы не должны полагаться на эти старые функции, но вместо этого включайте предупреждения своего компилятора, понимаете предупреждения и затем исправляете их правильно.
Ответ 4
Кроме того, линейные конгруэнтные PRNG имеют тенденцию создавать больше случайности на более высоких битах, чем на младших битах, поэтому для ограничения результата не используйте modulo, а вместо этого используйте что-то вроде:
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
(Это один из "Численных рецептов в C", ch.7)
Ответ 5
Сначала вам нужно засеять генератор, потому что он не генерирует реальные случайные числа!
Попробуйте следующее:
#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);
}
Ответ 6
Или, чтобы получить псевдослучайный int в диапазоне от 0 до 19,
например, вы могли бы использовать более высокие биты, например:
j = ((rand() >> 15) % 20;
Ответ 7
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;
}