Как сгенерировать случайный int в C? - PullRequest
510 голосов
/ 05 мая 2009

Есть ли функция для генерации случайного целого числа в C? Или мне придется использовать стороннюю библиотеку?

Ответы [ 24 ]

0 голосов
/ 16 января 2017

У меня была серьезная проблема с генератором псевдослучайных чисел в моем недавнем приложении: я неоднократно вызывал свою программу на C через скрипт pyhton, и я использовал в качестве семени следующий код:

srand(time(NULL))

Однако, так как:

  • rand сгенерирует ту же псевдослучайную последовательность, что и то же начальное число в srand (см. man srand);
  • Как уже говорилось, функция времени изменяется только секунда от секунды: если ваше приложение запускается несколько раз в течение одной секунды, time будет возвращать одно и то же значение каждый раз.

Моя программа сгенерировала ту же последовательность чисел. Вы можете сделать 3 вещи, чтобы решить эту проблему:

  1. смешать вывод времени с изменением некоторой другой информации при запуске (в моем приложении имя вывода):

    srand(time(NULL) | getHashOfString(outputName))
    

    Я использовал djb2 в качестве хэш-функции.

  2. Увеличение разрешения по времени. На моей платформе было доступно clock_gettime, поэтому я использую его:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec);
    
  3. Используйте оба метода вместе:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec | getHashOfString(outputName));
    

Вариант 3 гарантирует вам (насколько я знаю) лучшую начальную случайность, но это может создать разницу только в очень быстром приложении. На мой взгляд, вариант 2 - безопасная ставка.

0 голосов
/ 15 сентября 2013

Попробуйте, я собрал это из некоторых концепций, уже упомянутых выше:

/*    
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;
}
0 голосов
/ 06 августа 2016

Мое минималистичное решение должно работать для случайных чисел в диапазоне [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));
} 
0 голосов
/ 20 октября 2014

Услышав хорошее объяснение того, почему использование 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));

    const int 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);
}

и вот его вывод:

 $ gcc -o t3 t3.c
 $ ./t3 
        1666598  16.67%     
        1668630  16.69%
        1667682  16.68%
        1666049  16.66%
        1665948  16.66%
        1665093  16.65%
        total:  100.00%
 $ ./t3     
        1667634  16.68%
        1665914  16.66%
        1665542  16.66%
        1667828  16.68%
        1663649  16.64%
        1669433  16.69%
        total:  100.00%

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

Редактировать: было бы неплохо инициализировать PRNG чем-то лучшим, чем time(NULL).

...