Примечание : не используйте rand()для безопасности. Если вам нужен криптографически защищенный номер, посмотрите этот ответ .
#include<time.h>#include<stdlib.h>
srand(time(NULL));// Initialization, should only be called once.int r = rand();// Returns a pseudo-random integer between 0 and RAND_MAX.
Изменить : В Linux вы можете предпочесть использовать random и srandom .
+1 для простоты, но, вероятно, стоит подчеркнуть, что srand () вызывается только один раз . Кроме того, в многопоточном приложении вы можете убедиться, что состояние генератора сохраняется для каждого потока, и заполнить генератор один раз для каждого потока.
RBerteig
41
@trusktr, это сложно. Вот причина: time()меняется только один раз в секунду. Если вы начнете с time()каждого вызова rand(), вы получите одинаковое значение для каждого вызова в течение одной секунды. Но главная причина в том, что свойства rand()и функции, подобные этим, известны лучше всего для случая использования, когда они засеваются ровно один раз за цикл, а не при каждом вызове. Зависимость от «случайности» с непроверенными или недоказанными свойствами приводит к неприятностям.
RBerteig
9
@trusktr для простого линейного конгруэнтного генератора (который rand()обычно и есть), с которым посев с rand()в лучшем случае не будет иметь никакого эффекта вообще, а в худшем разрушит известные качества генератора. Это глубокий предмет. Начните с чтения Кнута Том 2 Глава 3 о случайных числах как лучшее введение в математику и подводные камни.
RBerteig
21
Избегайте предупреждения компилятора с приведением:srand((unsigned int)time(NULL));
GiovaMaster
9
Имейте в виду, что это все еще слабый способ видеть PRNG. Буквально в прошлом году вирус типа криптолокера в Linux допустил ошибку заполнения со временем, что резко сократило пространство поиска. Все, что вам нужно было сделать, это получить представление о том, когда произошла инфекция, а затем попробовать семена примерно в то же время. Последнее, что я слышал, лучший источник случайности - это / dev / urandom, который, предположительно, посеян из множества источников хаотичности, таких как температура на оборудовании. Однако, если все, что вы действительно хотите, чтобы ваша программа работала по-разному при каждом запуске, вышеприведенное решение подойдет.
Jemenake
238
rand()Функция <stdlib.h>возвращает псевдо-случайное число между 0 и RAND_MAX. Вы можете использовать, srand(unsigned int seed)чтобы установить семя.
Обычной практикой является использование %оператора в сочетании с rand()получением другого диапазона (хотя имейте в виду, что это несколько нарушает однородность). Например:
/* random int between 0 and 19 */int r = rand()%20;
Если вы действительно заботитесь о единообразии, вы можете сделать что-то вроде этого:
/* Returns an integer in the range [0, n).
*
* Uses rand(), and so is affected-by/affects the same seed.
*/int randint(int n){if((n -1)== RAND_MAX){return rand();}else{// Supporting larger values for n would requires an even more// elaborate implementation that combines multiple calls to rand()
assert (n <= RAND_MAX)// Chop off all of the values that would cause skew...int end = RAND_MAX / n;// truncate skew
assert (end >0);
end *= n;// ... and ignore results from rand() that fall above that limit.// (Worst case the loop condition should succeed 50% of the time,// so we can expect to bail out of this loop pretty quickly.)int r;while((r = rand())>= end);return r % n;}}
Это обычная практика , но не правильная. Смотрите это и это .
Lazer
35
@Lazer: Вот почему я сказал «хотя имейте в виду, что это несколько нарушает единообразие».
Лоуренс Гонсалвес
3
@AbhimanyuAryan Это %оператор модуля. Это дает вам остаток от целочисленного деления, поэтому x % nвсегда будет давать вам число между 0и n - 1(до тех пор, пока xи nоба положительны). Если вы все еще находите это сбивающим с толку, попробуйте написать программу, которая имеет iсчет от 0 до 100 и распечатывает i % nдля некоторых nиз вашего выбора меньше 100.
Лоуренс Гонсалвес
2
@necromancer Я пошел дальше и добавил совершенно единообразное решение.
Лоуренс Гонсалвес
2
@Lazer вторая ссылка, которую вы разместили, на самом деле все еще не идеально одинакова Приведение к двойному и обратно не помогает. Первое звено вы вывесили имеет совершенно однородное решение, хотя это будет цикл на много для небольших верхних границ. Я добавил к этому ответу совершенно равномерное решение, которое не должно повторяться даже для небольших верхних границ.
Лоуренс Гонсалвес
53
Если вам нужны безопасные случайные символы или целые числа:
В более широком смысле, используйте/dev/urandom , а не /dev/random. Не OpenSSL (или другие PRNG пользовательского пространства).
Например:
#include"sodium.h"int foo(){char myString[32];uint32_t myInt;if(sodium_init()<0){/* panic! the library couldn't be initialized, it is not safe to use */return1;}/* myString will be an array of 32 random bytes, not null-terminated */
randombytes_buf(myString,32);/* myInt will be a random number between 0 and 9 */
myInt = randombytes_uniform(10);}
randombytes_uniform() криптографически безопасен и непредвзят.
должен ли libsodium RNG быть посеян перед вызовом randombytes_buf?
user2199593
Просто позвоните sodium_init()в какой-то момент. Не беспокойтесь о RNG, он использует ядро.
Скотт
Примечание: я одобрил недавнее редактирование, sodium_init()хотя это не обязательно является частью моего примера, потому что это важная деталь.
Скотт Аркишевский
29
Давайте пройдем через это. Сначала мы используем функцию srand () для заполнения рандомизатора. По сути, компьютер может генерировать случайные числа на основе числа, которое передается в srand (). Если вы дали одинаковое начальное значение, то каждый раз будут генерироваться одни и те же случайные числа.
Следовательно, мы должны заполнить рандомизатор значением, которое всегда меняется. Мы делаем это, передавая значение текущего времени с помощью функции time ().
Теперь, когда мы вызываем rand (), каждый раз будет создаваться новое случайное число.
#include<stdio.h>int random_number(int min_num,int max_num);int main(void){
printf("Min : 1 Max : 40 %d\n", random_number(1,40));
printf("Min : 100 Max : 1000 %d\n",random_number(100,1000));return0;}int random_number(int min_num,int max_num){int result =0, low_num =0, hi_num =0;if(min_num < max_num){
low_num = min_num;
hi_num = max_num +1;// include max_num in output}else{
low_num = max_num +1;// include max_num in output
hi_num = min_num;}
srand(time(NULL));
result =(rand()%(hi_num - low_num))+ low_num;return result;}
Хороший код, но не очень хорошая идея, чтобы называть srand (time (NULL)); этот метод выдает тот же номер при вызове в цикле for.
RayOldProf
1
Предлагаемые правки, связанные с кодом, часто отклоняются. Кто-то сделал это здесь с комментарием «алгоритм был неправильным. Мог произвести большее число, чем максимальное». Сам не оценивал претензию.
Мартин Смит
1
Проблемы @Martin Smith: 1) должно быть else{ low_num=max_num; hi_num=min_num+1;2) не удается, когда hi_num - low_num > INT_MAX. 3) Опускает значения в редких ситуациях INT_MAX > hi_num - low_num > RAND_MAX.
chux - Восстановить Монику
1
Повторное заполнение этого кода приведет к тому, что эта функция выдаст одно и то же число, если она вызывается несколько раз в одну и ту же секунду. Если вы действительно хотите перезаряжать его, делайте это только раз в секунду.
Электра
1
Незначительный: hi_num = max_num + 1;отсутствует защита от переполнения.
chux - Восстановить Монику
25
Если вам нужны более качественные псевдослучайные числа, чем те, которые stdlibесть, посмотрите Mersenne Twister . Это тоже быстрее. Примеры реализации многочисленны, например, здесь .
+1: выглядит круто, но я просто делал игру в догадки. Если бы я собирался использовать генератор случайных чисел в бизнес-приложении, я бы определенно использовал это.
Креднс
4
Не используйте Mersenne Twister, используйте что-то хорошее, например, xoroshiro128 + или PCG. (Соответствующая ссылка.)
Veedrac
17
Стандартная функция C есть rand(). Это достаточно хорошо, чтобы раздавать карты для пасьянса, но это ужасно. Многие реализации rand()циклически проходят через короткий список чисел, а младшие биты имеют более короткие циклы. Путь, который вызывают некоторые программы, rand()ужасен, а рассчитать хорошее начальное число для передачи srand()довольно сложно.
Лучший способ генерировать случайные числа в C - это использовать стороннюю библиотеку, такую как OpenSSL. Например,
#include<stdint.h>#include<stdio.h>#include<stdlib.h>#include<openssl/rand.h>/* Random integer in [0, limit) */unsignedint random_uint(unsignedint limit){union{unsignedint i;unsignedchar c[sizeof(unsignedint)];} u;do{if(!RAND_bytes(u.c,sizeof(u.c))){
fprintf(stderr,"Can't get random bytes!\n");
exit(1);}}while(u.i <(-limit % limit));/* u.i < (2**size % limit) */return u.i % limit;}/* Random double in [0.0, 1.0) */double random_double(){union{uint64_t i;unsignedchar c[sizeof(uint64_t)];} u;if(!RAND_bytes(u.c,sizeof(u.c))){
fprintf(stderr,"Can't get random bytes!\n");
exit(1);}/* 53 bits / 2**53 */return(u.i >>11)*(1.0/9007199254740992.0);}int main(){
printf("Dice: %d\n",(int)(random_uint(6)+1));
printf("Double: %f\n", random_double());return0;}
Почему так много кода? Другие языки, такие как Java и Ruby, имеют функции для случайных целых чисел или чисел с плавающей точкой. OpenSSL дает только случайные байты, поэтому я пытаюсь имитировать, как Java или Ruby преобразуют их в целые числа или числа с плавающей точкой.
Для целых чисел мы хотим избежать смещения по модулю . Предположим, что мы получили случайные 4-значные целые числа rand() % 10000, но rand()можем вернуть только от 0 до 32767 (как это происходит в Microsoft Windows). Каждое число от 0 до 2767 будет появляться чаще, чем каждое число от 2768 до 9999. Чтобы устранить смещение, мы можем повторить, rand()пока значение меньше 2768, потому что 30000 значений от 2768 до 32767 отображаются равномерно на 10000 значений от 0 до 9999.
Для чисел с плавающей запятой мы хотим 53 случайных бита, потому что a doubleсодержит 53 бита точности (при условии, что это IEEE double). Если мы используем более 53 бит, мы получаем смещение округления. Некоторые программисты пишут подобный код rand() / (double)RAND_MAX, но rand()могут возвращать только 31 бит или только 15 бит в Windows.
OpenSSL берет свое RAND_bytes()начало, возможно, читая /dev/urandomв Linux. Если нам нужно много случайных чисел, было бы слишком медленно читать их все /dev/urandom, потому что они должны быть скопированы из ядра. Это позволяет OpenSSL генерировать больше случайных чисел из начального числа.
Подробнее о случайных числах:
Perl Perl_seed () является примером того, как рассчитать начальное число в Си для srand(). Он смешивает биты из текущего времени, идентификатора процесса и некоторых указателей, если он не может прочитать /dev/urandom.
Java API для java.util.Random описывает алгоритмы для удаления смещения из случайных целых чисел и упаковки 53 битов в случайные числа с плавающей точкой.
Спасибо за этот расширенный ответ. Обратите внимание, что из 24 текущих ответов на этот вопрос вы были единственными с дополнительной интерпретацией, чтобы иметь дело с float/ double, поэтому я уточнил вопрос, чтобы придерживаться intцифр, чтобы не сделать его слишком широким. Существуют и другие вопросы C, касающиеся конкретно float/ doubleслучайных значений, поэтому вы можете отправить свою вторую половину ответа на такие вопросы, как stackoverflow.com/questions/13408990/…
Cœur
11
Если ваша система поддерживает arc4randomсемейство функций, я бы рекомендовал использовать их вместо стандартной randфункции.
arc4random возвращает случайное 32-разрядное целое число без знака.
arc4random_bufпомещает случайный контент в свой параметр buf : void *. Количество контента определяетсяbytes : size_t параметром.
arc4random_uniformвозвращает случайное 32-разрядное целое число без знака, которое следует правилу:, 0 <= arc4random_uniform(limit) < limitгде предел также является 32-разрядным целым числом без знака.
arc4random_stirсчитывает данные /dev/urandomи передает их arc4random_addrandomдля дополнительной рандомизации своего внутреннего пула случайных чисел.
arc4random_addrandomиспользуется arc4random_stirдля заполнения внутреннего пула случайных чисел в соответствии с переданными ему данными.
Если у вас нет этих функций, но вы работаете в Unix, вы можете использовать этот код:
/* This is C, not C++ */#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<errno.h>#include<unistd.h>#include<stdlib.h>/* exit */#include<stdio.h>/* printf */int urandom_fd =-2;void urandom_init(){
urandom_fd = open("/dev/urandom", O_RDONLY);if(urandom_fd ==-1){int errsv = urandom_fd;
printf("Error opening [/dev/urandom]: %i\n", errsv);
exit(1);}}unsignedlong urandom(){unsignedlong buf_impl;unsignedlong*buf =&buf_impl;if(urandom_fd ==-2){
urandom_init();}/* Read 4 bytes, or 32 bits into *buf, which points to buf_impl */
read(urandom_fd, buf,sizeof(long));return buf_impl;}
urandom_initФункция открывает /dev/urandomустройство, и помещает дескриптор файла в urandom_fd.
urandomФункция в основном такая же , как призыв к rand, за исключением более безопасным, и он возвращает long(легко изменяемый).
Однако /dev/urandomможет быть немного медленным, поэтому рекомендуется использовать его в качестве начального числа для другого генератора случайных чисел.
Если ваша система не имеет /dev/urandom, но действительно есть /dev/randomили подобный файл, то вы можете просто изменить путь , пройденный к openв urandom_init. Вызовы и API , используемые в urandom_initи urandomявляются (я считаю) POSIX-совместимые, и , как таковые, должны работать на большинстве, если не во все совместимые системы POSIX.
Примечания: Чтение из /dev/urandomНЕ будет блокироваться, если энтропии недостаточно, поэтому значения, сгенерированные в таких обстоятельствах, могут быть криптографически небезопасными. Если вы беспокоитесь об этом, то используйте /dev/random, который всегда будет блокировать, если энтропии недостаточно.
Если вы работаете в другой системе (например, в Windows), то используйте randили какой-нибудь внутренний зависящий от платформы непереносимый API.
Обертка функции для urandom, randили arc4randomвызовов:
STL не существует для C. Вы должны позвонить rand, или еще лучше random. Они объявлены в заголовке стандартной библиотеки stdlib.h. randэто POSIX, randomэто функция спецификации BSD.
Разница между randи в randomтом, что randomвозвращает гораздо более пригодное для использования 32-разрядное случайное число и randобычно возвращает 16-разрядное число. Страницы руководства BSD показывают, что младшие биты randявляются циклическими и предсказуемыми, поэтому randпотенциально бесполезны для небольших чисел.
@Neil - так как все ответы до сих пор упоминают STL, я подозреваю, что вопрос был быстро отредактирован, чтобы удалить ненужную ссылку.
Майкл Берр
rand () не бесполезен для небольших чисел - вы можете сдвинуть их и использовать только более случайные старшие биты, если вам это действительно нужно.
Крис Латс
@ Крис, вы можете, если размер случайного числа известен, но если требуемый размер случайного числа изменяется во время выполнения (например, перетасовывание динамического массива и т. Д.), Будет трудно обойти такую оговорку.
Вы хотите использовать rand(). Примечание ( ОЧЕНЬ ВАЖНО ): обязательно установите начальное значение для функции ранда. Если вы этого не сделаете, ваши случайные числа не являются действительно случайными . Это очень, очень, очень важно. К счастью, вы можете использовать некоторую комбинацию таймера системных тиков и даты, чтобы получить хорошее начальное число.
Два момента: а) ваши случайные числа не являются «по-настоящему» случайными, независимо от того, как вы посеете генератор. И б) очень удобно, чтобы псевдослучайная последовательность всегда была одинаковой во многих обстоятельствах - например, для тестирования.
16
если ОЧЕНЬ ВАЖНО, чтобы ваш номер был действительно случайным, вам не следует использовать функцию rand ().
Tylerl
1
Значения от rand вовсе не являются «действительно» случайными, независимо от того, задано ли начальное число или нет. При известном семени последовательность предсказуема. «Истинно» генерация случайных чисел затруднена. Нет энтропии, связанной с рандом.
Dreamlax
2
Конечно, они будут - генератор засеян для вас библиотекой (вероятно, в ноль, но это действительное начальное число).
4
Ах, но известный алгоритм / известное начальное значение имеет важное значение для отладки любой программы, которая использует случайные числа. Нет ничего необычного в том, чтобы записать начальное число, используемое вместе с прогоном моделирования, чтобы его можно было воссоздать для более подробного анализа. Не вызывать srand () вообще эквивалентно вызову srand (1).
RBerteig
4
FWIW, ответ в том, что да, есть stdlib.hфункция называется rand; эта функция настроена в первую очередь на скорость и распределение, а не на непредсказуемость. Почти все встроенные случайные функции для различных языков и сред используют эту функцию по умолчанию. Существуют также «криптографические» генераторы случайных чисел, которые гораздо менее предсказуемы, но работают намного медленнее. Их следует использовать в любых приложениях, связанных с безопасностью.
Добавление srand (rand ()) не увеличивает случайность последовательности, если эта программа выполняется несколько раз в течение 1 секунды. time (NULL) будет по-прежнему возвращать одно и то же значение для каждого из них, первый rand () будет возвращать ту же самую длину, а второй вызов srand () будет с тем же значением, в результате все равно будет иметь одинаковую случайную последовательность. Использование адреса argc может помочь, только если гарантируется, что этот адрес будет отличаться при каждом выполнении программы, что не всегда верно.
theferrit32
3
Ну, STL - это C ++, а не C, поэтому я не знаю, что вы хотите. Если вы хотите C, однако, есть rand()и srand()функции:
int rand(void);void srand(unsigned seed);
Они оба являются частью ANSI C. Существует также random()функция:
long random(void);
Но, насколько я могу судить, random()это не стандарт ANSI C. Сторонняя библиотека может быть неплохой идеей, но все зависит от того, насколько случайным образом число вам действительно нужно сгенерировать.
Вы также можете поймать случайное число из любого онлайн-сервиса, например random.org Bounty, если вы включите портативный, эффективный способ сделать это в C.
MD XF
2
#include<stdio.h>#include<stdlib.h>void main(){int visited[100];int randValue, a, b, vindex =0;
randValue =(rand()%100)+1;while(vindex <100){for(b =0; b < vindex; b++){if(visited[b]== randValue){
randValue =(rand()%100)+1;
b =0;}}
visited[vindex++]= randValue;}for(a =0; a <100; a++)
printf("%d ", visited[a]);}
В тот момент, когда я сделал этот комментарий, у меня не было универсальных прав на редактирование, и, как правило, изменения кода, которые изменили фактический ответ, будут отклонены. Если вы не хотите исправить свой ответ, я могу.
b4hand
Если вы намеревались создать случайную перестановку уникальных значений, этот код все еще содержит ошибку. Он дважды выдает значение 84 и не выдает значение 48. Более того, он не заполняет генератор случайных чисел, поэтому последовательность при каждом выполнении одинакова.
b4hand
1
переменные a и b определены в этом коде. Это безошибочно .. нет также синтаксиса и логической ошибки.
Мухаммед Садик,
Неправильно. Я уже рукой подтвердил вывод, как я уже говорил.
b4hand
1
#include<stdio.h>#include<dos.h>int random(int range);int main(void){
printf("%d", random(10));return0;}int random(int range){struct time t;int r;
gettime(&t);
r = t.ti_sec % range;return r;}
На современных процессорах x86_64 вы можете использовать аппаратный генератор случайных чисел через _rdrand64_step()
Пример кода:
#include<immintrin.h>uint64_t randVal;if(!_rdrand64_step(&randVal)){// Report an error here: random number generation has failed!}// If no error occured, randVal contains a random 64-bit number
#include<stdio.h>#include<stdlib.h>#include<time.h>//generate number in range [min,max)int random(int min,int max){int number = min + rand()%(max - min);return number;}//Driver codeint main(){
srand(time(NULL));for(int i =1; i <=10; i++){
printf("%d\t", random(10,100));}return0;}
Услышав хорошее объяснение того, почему использование rand()для получения равномерно распределенных случайных чисел в заданном диапазоне является плохой идеей, я решил взглянуть на то, насколько искаженным является результат. Мой тестовый пример был честным бросанием игральных костей. Вот код C:
#include<stdio.h>#include<stdlib.h>#include<time.h>int main(int argc,char*argv[]){int i;int dice[6];for(i =0; i <6; i++)
dice[i]=0;
srand(time(NULL));constint TOTAL =10000000;for(i =0; i < TOTAL; i++)
dice[(rand()%6)]+=1;double pers =0.0, tpers =0.0;for(i =0; i <6; i++){
pers =(dice[i]*100.0)/ TOTAL;
printf("\t%1d %5.2f%%\n", dice[i], pers);
tpers += pers;}
printf("\ttotal: %6.2f%%\n", tpers);}
rand () может не пройти другие тесты на случайность, такие как несгибаемые тесты . rand () отличается от платформы к платформе; Значения rand () из GNU / Linux могут быть лучше, чем значения из BSD или Windows.
Джордж Келер
Это недопустимый способ проверки на случайность.
Veedrac
Зависит от цели и модели угрозы / риска. Для криптографически надежного RNG - конечно, используйте RDRAND (или RDSEED). Для простого метателя игральных костей (не на уровне казино) ИМХО вышеупомянутого должно быть достаточно. Ключевое слово " достаточно хорошо ".
Мышь
0
У меня была серьезная проблема с генератором псевдослучайных чисел в моем недавнем приложении: я неоднократно вызывал свою программу на C через скрипт pyhton, и я использовал в качестве семени следующий код:
srand(time(NULL))
Тем не менее, так как:
rand сгенерирует ту же псевдослучайную последовательность, что и srand (см. man srand);
Как уже говорилось, функция времени меняется только секунда от секунды: если ваше приложение запускается несколько раз в течение одной секунды, оно timeбудет возвращать одно и то же значение каждый раз.
Моя программа генерировала ту же последовательность чисел. Вы можете сделать 3 вещи, чтобы решить эту проблему:
смешать вывод времени с некоторой другой информацией, изменяющейся при запуске (в моем приложении имя вывода):
Вариант 3 гарантирует вам (насколько я знаю) лучшую начальную случайность, но это может создать разницу только в очень быстром приложении. На мой взгляд, вариант 2 - безопасная ставка.
Даже при такой эвристике не полагайтесь на rand () для криптографических данных.
Доменюк
rand()не должен использоваться для криптографических данных, я согласен. По крайней мере, для меня в моем приложении не было криптографических данных, поэтому для меня это был нормальный метод.
Колдар
0
Несмотря на все предложения людей rand()здесь, вы не хотите использовать, rand()если вам не нужно! Случайные числа, которые rand()производят, часто очень плохие. Чтобы процитировать со страницы руководства Linux:
Версии rand()и srand()в библиотеке Linux C используют тот же генератор случайных чисел, что random(3)и srandom(3), поэтому биты младшего разряда должны быть такими же случайными, как биты старшего разряда. Однако в более старых реализациях rand () и в текущих реализациях в разных системах биты младшего разряда гораздо менее случайны, чем биты старшего порядка . Не используйте эту функцию в приложениях, предназначенных для переноса, когда необходима хорошая случайность. ( Используйте random(3)вместо. )
Относительно переносимости, random()также определяется стандартом POSIX уже довольно давно. rand()старше, он появился уже в первой спецификации POSIX.1 (IEEE Std 1003.1-1988), тогда как random()впервые появился в POSIX.1-2001 (IEEE Std 1003.1-2001), но текущий стандарт POSIX уже POSIX.1-2008 (IEEE Std 1003.1-2008), который получил обновление всего год назад (IEEE Std 1003.1-2008, издание 2016 г.). Так что я бы рассмотрелrandom() очень портативным.
POSIX.1-2001 также представил lrand48()и mrand48()функции, смотрите здесь :
Это семейство функций должно генерировать псевдослучайные числа с использованием линейного конгруэнтного алгоритма и 48-разрядной целочисленной арифметики.
И довольно хороший псевдослучайный источник - это arc4random()функция, которая доступна во многих системах. Не является частью какого-либо официального стандарта, появившегося в BSD в 1997 году, но вы можете найти его в таких системах, как Linux и macOS / iOS.
@ BjörnLindqvist Windows также не является системой POSIX; это практически единственная система на рынке, которая не поддерживает, по крайней мере, базовые API POSIX (которые поддерживают даже заблокированные системы, такие как iOS). Windows только поддерживает, rand()поскольку это также требуется стандартом C. Для всего остального вам нужно специальное решение только для Windows, как обычно. #ifdef _WIN32Это фраза, которую вы будете чаще всего видеть в кроссплатформенном коде, который хочет поддерживать Windows, а также обычно есть одно решение, которое работает со всеми системами, и то, которое требуется только для Windows.
Меки
0
Для приложений Linux C:
Это мой переработанный код из приведенного выше ответа, который следует моим практикам кода C и возвращает случайный буфер любого размера (с правильными кодами возврата и т. Д.). Обязательно позвоните urandom_open()один раз в начале вашей программы.
int gUrandomFd =-1;int urandom_open(void){if(gUrandomFd ==-1){
gUrandomFd = open("/dev/urandom", O_RDONLY);}if(gUrandomFd ==-1){
fprintf(stderr,"Error opening /dev/urandom: errno [%d], strerrer [%s]\n",
errno, strerror(errno));return-1;}else{return0;}}void urandom_close(void){
close(gUrandomFd);
gUrandomFd =-1;}//// This link essentially validates the merits of /dev/urandom:// http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers///int getRandomBuffer(uint8_t*buf,int size){int ret =0;// Return valueif(gUrandomFd ==-1){
fprintf(stderr,"Urandom (/dev/urandom) file not open\n");return-1;}
ret = read(gUrandomFd, buf, size);if(ret != size){
fprintf(stderr,"Only read [%d] bytes, expected [%d]\n",
ret, size);return-1;}else{return0;}}
Мое минималистичное решение должно работать для случайных чисел в диапазоне [min, max). Используйте srand(time(NULL))перед вызовом функции.
int range_rand(int min_num,int max_num){if(min_num >= max_num){
fprintf(stderr,"min_num is greater or equal than max_num!\n");}return min_num +(rand()%(max_num - min_num));}
Попробуйте это, я собрал это из некоторых концепций, уже упомянутых выше:
/*
Uses the srand() function to seed the random number generator based on time value,
then returns an integer in the range 1 to max. Call this with random(n) where n is an integer, and you get an integer as a return value.
*/int random(int max){
srand((unsigned) time(NULL));return(rand()% max)+1;}
Этот код не очень хорош. Звонить srand()каждый раз, когда вы хотите позвонить rand(), это ужасная идея. Поскольку time()обычно возвращает значение в секундах, быстрый вызов этой функции вернет то же «случайное» значение.
Доменная печь
3
Эта функция будет перепутана с random()функцией Unix .
srand
: зачем звонить только один раз .Ответы:
Изменить : В Linux вы можете предпочесть использовать random и srandom .
источник
time()
меняется только один раз в секунду. Если вы начнете сtime()
каждого вызоваrand()
, вы получите одинаковое значение для каждого вызова в течение одной секунды. Но главная причина в том, что свойстваrand()
и функции, подобные этим, известны лучше всего для случая использования, когда они засеваются ровно один раз за цикл, а не при каждом вызове. Зависимость от «случайности» с непроверенными или недоказанными свойствами приводит к неприятностям.rand()
обычно и есть), с которым посев сrand()
в лучшем случае не будет иметь никакого эффекта вообще, а в худшем разрушит известные качества генератора. Это глубокий предмет. Начните с чтения Кнута Том 2 Глава 3 о случайных числах как лучшее введение в математику и подводные камни.srand((unsigned int)time(NULL));
rand()
Функция<stdlib.h>
возвращает псевдо-случайное число между 0 иRAND_MAX
. Вы можете использовать,srand(unsigned int seed)
чтобы установить семя.Обычной практикой является использование
%
оператора в сочетании сrand()
получением другого диапазона (хотя имейте в виду, что это несколько нарушает однородность). Например:Если вы действительно заботитесь о единообразии, вы можете сделать что-то вроде этого:
источник
%
оператор модуля. Это дает вам остаток от целочисленного деления, поэтомуx % n
всегда будет давать вам число между0
иn - 1
(до тех пор, покаx
иn
оба положительны). Если вы все еще находите это сбивающим с толку, попробуйте написать программу, которая имеетi
счет от 0 до 100 и распечатываетi % n
для некоторыхn
из вашего выбора меньше 100.Если вам нужны безопасные случайные символы или целые числа:
Что касается того, как безопасно генерировать случайные числа на разных языках программирования , вам нужно выполнить одно из следующих действий:
randombytes
API/dev/urandom
, а не/dev/random
. Не OpenSSL (или другие PRNG пользовательского пространства).Например:
randombytes_uniform()
криптографически безопасен и непредвзят.источник
sodium_init()
в какой-то момент. Не беспокойтесь о RNG, он использует ядро.sodium_init()
хотя это не обязательно является частью моего примера, потому что это важная деталь.Давайте пройдем через это. Сначала мы используем функцию srand () для заполнения рандомизатора. По сути, компьютер может генерировать случайные числа на основе числа, которое передается в srand (). Если вы дали одинаковое начальное значение, то каждый раз будут генерироваться одни и те же случайные числа.
Следовательно, мы должны заполнить рандомизатор значением, которое всегда меняется. Мы делаем это, передавая значение текущего времени с помощью функции time ().
Теперь, когда мы вызываем rand (), каждый раз будет создаваться новое случайное число.
источник
else{ low_num=max_num; hi_num=min_num+1;
2) не удается, когдаhi_num - low_num > INT_MAX
. 3) Опускает значения в редких ситуацияхINT_MAX > hi_num - low_num > RAND_MAX
.hi_num = max_num + 1;
отсутствует защита от переполнения.Если вам нужны более качественные псевдослучайные числа, чем те, которые
stdlib
есть, посмотрите Mersenne Twister . Это тоже быстрее. Примеры реализации многочисленны, например, здесь .источник
Стандартная функция C есть
rand()
. Это достаточно хорошо, чтобы раздавать карты для пасьянса, но это ужасно. Многие реализацииrand()
циклически проходят через короткий список чисел, а младшие биты имеют более короткие циклы. Путь, который вызывают некоторые программы,rand()
ужасен, а рассчитать хорошее начальное число для передачиsrand()
довольно сложно.Лучший способ генерировать случайные числа в C - это использовать стороннюю библиотеку, такую как OpenSSL. Например,
Почему так много кода? Другие языки, такие как Java и Ruby, имеют функции для случайных целых чисел или чисел с плавающей точкой. OpenSSL дает только случайные байты, поэтому я пытаюсь имитировать, как Java или Ruby преобразуют их в целые числа или числа с плавающей точкой.
Для целых чисел мы хотим избежать смещения по модулю . Предположим, что мы получили случайные 4-значные целые числа
rand() % 10000
, ноrand()
можем вернуть только от 0 до 32767 (как это происходит в Microsoft Windows). Каждое число от 0 до 2767 будет появляться чаще, чем каждое число от 2768 до 9999. Чтобы устранить смещение, мы можем повторить,rand()
пока значение меньше 2768, потому что 30000 значений от 2768 до 32767 отображаются равномерно на 10000 значений от 0 до 9999.Для чисел с плавающей запятой мы хотим 53 случайных бита, потому что a
double
содержит 53 бита точности (при условии, что это IEEE double). Если мы используем более 53 бит, мы получаем смещение округления. Некоторые программисты пишут подобный кодrand() / (double)RAND_MAX
, ноrand()
могут возвращать только 31 бит или только 15 бит в Windows.OpenSSL берет свое
RAND_bytes()
начало, возможно, читая/dev/urandom
в Linux. Если нам нужно много случайных чисел, было бы слишком медленно читать их все/dev/urandom
, потому что они должны быть скопированы из ядра. Это позволяет OpenSSL генерировать больше случайных чисел из начального числа.Подробнее о случайных числах:
srand()
. Он смешивает биты из текущего времени, идентификатора процесса и некоторых указателей, если он не может прочитать/dev/urandom
.источник
float
/double
, поэтому я уточнил вопрос, чтобы придерживатьсяint
цифр, чтобы не сделать его слишком широким. Существуют и другие вопросы C, касающиеся конкретноfloat
/double
случайных значений, поэтому вы можете отправить свою вторую половину ответа на такие вопросы, как stackoverflow.com/questions/13408990/…Если ваша система поддерживает
arc4random
семейство функций, я бы рекомендовал использовать их вместо стандартнойrand
функции.arc4random
Семейство включает в себя:arc4random
возвращает случайное 32-разрядное целое число без знака.arc4random_buf
помещает случайный контент в свой параметрbuf : void *
. Количество контента определяетсяbytes : size_t
параметром.arc4random_uniform
возвращает случайное 32-разрядное целое число без знака, которое следует правилу:,0 <= arc4random_uniform(limit) < limit
где предел также является 32-разрядным целым числом без знака.arc4random_stir
считывает данные/dev/urandom
и передает ихarc4random_addrandom
для дополнительной рандомизации своего внутреннего пула случайных чисел.arc4random_addrandom
используетсяarc4random_stir
для заполнения внутреннего пула случайных чисел в соответствии с переданными ему данными.Если у вас нет этих функций, но вы работаете в Unix, вы можете использовать этот код:
urandom_init
Функция открывает/dev/urandom
устройство, и помещает дескриптор файла вurandom_fd
.urandom
Функция в основном такая же , как призыв кrand
, за исключением более безопасным, и он возвращаетlong
(легко изменяемый).Однако
/dev/urandom
может быть немного медленным, поэтому рекомендуется использовать его в качестве начального числа для другого генератора случайных чисел.Если ваша система не имеет
/dev/urandom
, но действительно есть/dev/random
или подобный файл, то вы можете просто изменить путь , пройденный кopen
вurandom_init
. Вызовы и API , используемые вurandom_init
иurandom
являются (я считаю) POSIX-совместимые, и , как таковые, должны работать на большинстве, если не во все совместимые системы POSIX.Примечания: Чтение из
/dev/urandom
НЕ будет блокироваться, если энтропии недостаточно, поэтому значения, сгенерированные в таких обстоятельствах, могут быть криптографически небезопасными. Если вы беспокоитесь об этом, то используйте/dev/random
, который всегда будет блокировать, если энтропии недостаточно.Если вы работаете в другой системе (например, в Windows), то используйте
rand
или какой-нибудь внутренний зависящий от платформы непереносимый API.Обертка функции для
urandom
,rand
илиarc4random
вызовов:источник
STL не существует для C. Вы должны позвонить
rand
, или еще лучшеrandom
. Они объявлены в заголовке стандартной библиотекиstdlib.h
.rand
это POSIX,random
это функция спецификации BSD.Разница между
rand
и вrandom
том, чтоrandom
возвращает гораздо более пригодное для использования 32-разрядное случайное число иrand
обычно возвращает 16-разрядное число. Страницы руководства BSD показывают, что младшие битыrand
являются циклическими и предсказуемыми, поэтомуrand
потенциально бесполезны для небольших чисел.источник
extern int rand(void);
иextern void srand(unsigned int);
.Посмотрите на ISAAC (Indirection, Shift, Accumulate, Add и Count). Он равномерно распределен и имеет среднюю продолжительность цикла 2 ^ 8295.
источник
Это хороший способ получить случайное число между двумя числами по вашему выбору.
Выходной первый раз: 39
Выходной второй раз: 61
Выходной третий раз: 65
Вы можете изменить значения после
randnum
на любое число, которое вы выберете, и оно сгенерирует для вас случайное число между этими двумя числами.источник
Вы хотите использовать
rand()
. Примечание ( ОЧЕНЬ ВАЖНО ): обязательно установите начальное значение для функции ранда. Если вы этого не сделаете, ваши случайные числа не являются действительно случайными . Это очень, очень, очень важно. К счастью, вы можете использовать некоторую комбинацию таймера системных тиков и даты, чтобы получить хорошее начальное число.источник
FWIW, ответ в том, что да, есть
stdlib.h
функция называетсяrand
; эта функция настроена в первую очередь на скорость и распределение, а не на непредсказуемость. Почти все встроенные случайные функции для различных языков и сред используют эту функцию по умолчанию. Существуют также «криптографические» генераторы случайных чисел, которые гораздо менее предсказуемы, но работают намного медленнее. Их следует использовать в любых приложениях, связанных с безопасностью.источник
Надеюсь, это немного более случайно, чем просто использование
srand(time(NULL))
.источник
Ну, STL - это C ++, а не C, поэтому я не знаю, что вы хотите. Если вы хотите C, однако, есть
rand()
иsrand()
функции:Они оба являются частью ANSI C. Существует также
random()
функция:Но, насколько я могу судить,
random()
это не стандарт ANSI C. Сторонняя библиотека может быть неплохой идеей, но все зависит от того, насколько случайным образом число вам действительно нужно сгенерировать.источник
C Программа для генерации случайного числа от 9 до 50
В общем, мы можем генерировать случайное число между lowerLimit и upperLimit-1
то есть lowerLimit включительно или, скажем, r ∈ [lowerLimit, upperLimit)
источник
rand()
это наиболее удобный способ генерации случайных чисел.Вы также можете поймать случайное число из любого онлайн-сервиса, например random.org.
источник
источник
источник
На современных процессорах x86_64 вы можете использовать аппаратный генератор случайных чисел через
_rdrand64_step()
Пример кода:
источник
источник
Услышав хорошее объяснение того, почему использование
rand()
для получения равномерно распределенных случайных чисел в заданном диапазоне является плохой идеей, я решил взглянуть на то, насколько искаженным является результат. Мой тестовый пример был честным бросанием игральных костей. Вот код C:и вот его вывод:
Я не знаю, насколько вам нужны ваши случайные числа, но вышеприведенное выглядит достаточно равномерным для большинства нужд.
Изменить: было бы неплохо инициализировать PRNG с чем-то лучше, чем
time(NULL)
.источник
У меня была серьезная проблема с генератором псевдослучайных чисел в моем недавнем приложении: я неоднократно вызывал свою программу на C через скрипт pyhton, и я использовал в качестве семени следующий код:
Тем не менее, так как:
man srand
);time
будет возвращать одно и то же значение каждый раз.Моя программа генерировала ту же последовательность чисел. Вы можете сделать 3 вещи, чтобы решить эту проблему:
смешать вывод времени с некоторой другой информацией, изменяющейся при запуске (в моем приложении имя вывода):
Я использовал djb2 в качестве хэш-функции.
Увеличьте разрешение по времени. На моей платформе
clock_gettime
был доступен, поэтому я использую его:Используйте оба метода вместе:
Вариант 3 гарантирует вам (насколько я знаю) лучшую начальную случайность, но это может создать разницу только в очень быстром приложении. На мой взгляд, вариант 2 - безопасная ставка.
источник
rand()
не должен использоваться для криптографических данных, я согласен. По крайней мере, для меня в моем приложении не было криптографических данных, поэтому для меня это был нормальный метод.Несмотря на все предложения людей
rand()
здесь, вы не хотите использовать,rand()
если вам не нужно! Случайные числа, которыеrand()
производят, часто очень плохие. Чтобы процитировать со страницы руководства Linux:Относительно переносимости,
random()
также определяется стандартом POSIX уже довольно давно.rand()
старше, он появился уже в первой спецификации POSIX.1 (IEEE Std 1003.1-1988), тогда какrandom()
впервые появился в POSIX.1-2001 (IEEE Std 1003.1-2001), но текущий стандарт POSIX уже POSIX.1-2008 (IEEE Std 1003.1-2008), который получил обновление всего год назад (IEEE Std 1003.1-2008, издание 2016 г.). Так что я бы рассмотрелrandom()
очень портативным.POSIX.1-2001 также представил
lrand48()
иmrand48()
функции, смотрите здесь :И довольно хороший псевдослучайный источник - это
arc4random()
функция, которая доступна во многих системах. Не является частью какого-либо официального стандарта, появившегося в BSD в 1997 году, но вы можете найти его в таких системах, как Linux и macOS / iOS.источник
random()
не существует в Windows.rand()
поскольку это также требуется стандартом C. Для всего остального вам нужно специальное решение только для Windows, как обычно.#ifdef _WIN32
Это фраза, которую вы будете чаще всего видеть в кроссплатформенном коде, который хочет поддерживать Windows, а также обычно есть одно решение, которое работает со всеми системами, и то, которое требуется только для Windows.Для приложений Linux C:
Это мой переработанный код из приведенного выше ответа, который следует моим практикам кода C и возвращает случайный буфер любого размера (с правильными кодами возврата и т. Д.). Обязательно позвоните
urandom_open()
один раз в начале вашей программы.источник
Мое минималистичное решение должно работать для случайных чисел в диапазоне
[min, max)
. Используйтеsrand(time(NULL))
перед вызовом функции.источник
Попробуйте это, я собрал это из некоторых концепций, уже упомянутых выше:
источник
srand()
каждый раз, когда вы хотите позвонитьrand()
, это ужасная идея. Посколькуtime()
обычно возвращает значение в секундах, быстрый вызов этой функции вернет то же «случайное» значение.random()
функцией Unix .