Как получить определенный диапазон чисел из rand ()? - PullRequest
32 голосов
/ 30 июля 2009
srand(time(null));

printf("%d", rand());

Дает случайное число высокого диапазона (0-32000ish), но мне нужно только 0-63 или 0-127, хотя я не уверен, как это сделать. Любая помощь?

Ответы [ 17 ]

57 голосов
/ 30 июля 2009
rand() % (max_number + 1 - minimum_number) + minimum_number

Итак, для 0-65:

rand() % (65 + 1 - 0) + 0

(очевидно, вы можете оставить 0 выключенным, но это для полноты).

Обратите внимание, что это немного смещает случайность, но, вероятно, не о чем беспокоиться, если вы не делаете что-то особенно чувствительное.

16 голосов
/ 30 июля 2009

проверьте здесь

http://c -faq.com / Lib / randrange.html

Для любого из этих методов, при необходимости, просто сместить диапазон; числа в диапазоне [M, N] могут быть сгенерированы с чем-то вроде

M + rand() / (RAND_MAX / (N - M + 1) + 1)
9 голосов
/ 22 августа 2013

Вы можете использовать это:

int random(int min, int max){
   return min + rand() / (RAND_MAX / (max - min + 1) + 1);
}

Из:

список часто задаваемых вопросов comp.lang.c · Вопрос 13.16

В: Как я могу получить случайные целые числа в определенном диапазоне?

A: Очевидный путь,

rand() % N        /* POOR */

(который пытается вернуть числа от 0 до N-1) плохо, потому что Младшие биты многих генераторов случайных чисел вызывают беспокойство не случайно. (См. Вопрос 13.18 .) Лучший метод - что-то вроде

(int)((double)rand() / ((double)RAND_MAX + 1) * N)

Если вы не хотите использовать число с плавающей запятой, другой метод -

rand() / (RAND_MAX / N + 1)

Если вам просто нужно что-то сделать с вероятностью 1 / N, вы можете использовать

if(rand() < (RAND_MAX+1u) / N)

Все эти методы, очевидно, требуют знания RAND_MAX (который ANSI #defines в ) и предполагают, что N намного меньше, чем RAND_MAX. Когда N близко к RAND_MAX, и если диапазон случайного числа генератор не кратен N (т.е. если (RAND_MAX + 1)% N! = 0), все из этих методов выходят из строя: некоторые выходы происходят чаще, чем другие. (Использование плавающей запятой не помогает; проблема в том, что rand возвращает RAND_MAX + 1 различных значений, которые не всегда могут быть равномерно разделить на N ведер.) Если это проблема, об единственном Вы можете сделать это, чтобы вызвать rand несколько раз, отбрасывая определенные значения:

unsigned int x = (RAND_MAX + 1u) / N;
unsigned int y = x * N;
unsigned int r;
do {
  r = rand();
} while(r >= y);
return r / x;

Для любого из этих методов легко сместить диапазон, если необходимо; числа в диапазоне [M, N] могут быть сгенерированы с что-то вроде

M + rand() / (RAND_MAX / (N - M + 1) + 1)

(Заметьте, кстати, что RAND_MAX является константой , сообщающей вам, что фиксированный диапазон функции библиотеки C rand . Вы не можете установить RAND_MAX к другому значению, и нет способа запросить rand вернуть числа в другом диапазоне.)

Если вы начинаете с генератора случайных чисел, который возвращает значения с плавающей точкой от 0 до 1 (например, последняя версия PM и , о котором идет речь в вопросе 13.15 или drand48, о котором идет речь 13.21 ) все, что вам нужно сделать, чтобы получить целые числа от 0 до N-1, это умножьте выходную мощность этого генератора на N:

(int)(drand48() * N)

Дополнительные ссылки

Ссылки: K & R2 Sec. 7.8.7 с. 168
PCS Sec. 11 стр. 172

Цитата: http://c -faq.com / lib / randrange.html

6 голосов
/ 30 июля 2009

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

Рассмотрим этот крайний пример, предположим, что вы хотелисимулируйте бросок монеты, возвращая либо 0, либо 1. Вы можете сделать это:

isHeads = ( rand() % 2 ) == 1;

Выглядит достаточно безобидно, верно?Предположим, что RAND_MAX только 3. Это, конечно, намного выше, но суть здесь в том, что существует смещение, когда вы используете модуль, который не делит RAND_MAX равномерно.Если вам нужны высококачественные случайные числа, у вас возникнет проблема.

Рассмотрим мой пример.Возможные результаты:

rand()  freq. rand() % 2
0       1/3   0
1       1/3   1
2       1/3   0

Следовательно, "хвосты" будут встречаться в два раза чаще, чем "головы"!

Мистер.Этвуд обсуждает этот вопрос в этой статье ужасов кодирования

5 голосов
/ 30 июля 2009

Как уже отмечали другие, простое использование модуля искажает вероятности для отдельных чисел, поэтому предпочтение отдается меньшим числам.

Очень изобретательное и хорошее решение этой проблемы используется в классе java.util.Random Java:

public int nextInt(int n) {
    if (n <= 0)
        throw new IllegalArgumentException("n must be positive");

    if ((n & -n) == n)  // i.e., n is a power of 2
        return (int)((n * (long)next(31)) >> 31);

    int bits, val;
    do {
        bits = next(31);
        val = bits % n;
    } while (bits - val + (n-1) < 0);
    return val;
}

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

Важной частью в этом фрагменте кода является условие для цикла while, который отклоняет числа, попадающие в диапазон чисел, что в противном случае привело бы к неравномерному распределению.

3 голосов
/ 30 июля 2009
double scale = 1.0 / ((double) RAND_MAX + 1.0);
int min, max;
...
rval = (int)(rand() * scale * (max - min + 1) + min);
2 голосов
/ 30 июля 2009

Обновлено, чтобы не использовать # define

double RAND(double min, double max)
{
    return (double)rand()/(double)RAND_MAX * (max - min) + min;
}
2 голосов
/ 30 июля 2009

Наивный способ сделать это:

int myRand = rand() % 66; // for 0-65

Вероятно, это будет слегка неравномерное распределение (в зависимости от вашего максимального значения), но оно довольно близко.

Чтобы объяснить, почему это не совсем равномерно, рассмотрим этот очень упрощенный пример:
Предположим, что RAND_MAX равен 4, а вы хотите число от 0 до 2. Возможные значения, которые вы можете получить, показаны в этой таблице:

rand()   |  rand() % 3
---------+------------
0        |  0
1        |  1
2        |  2
3        |  0

Видишь проблему? Если ваше максимальное значение не является четным делителем RAND_MAX, вы с большей вероятностью выберете маленькие значения. Однако, поскольку RAND_MAX обычно равен 32767, смещение, вероятно, будет достаточно маленьким, чтобы сойти с рук в большинстве случаев.

Существуют различные способы обойти эту проблему; см. здесь для объяснения того, как Java Random справляется с этим.

2 голосов
/ 30 июля 2009

Если вы не слишком заботитесь о «случайности» младших битов, просто rand ()% HI_VAL.

Также:

(double)rand() / (double)RAND_MAX;  // lazy way to get [0.0, 1.0)
1 голос
/ 30 июля 2009

rand () вернет числа от 0 до RAND_MAX, что составляет не менее 32767.

Если вы хотите получить число в диапазоне, вы можете просто использовать модуль.

int value = rand() % 66; // 0-65

Для большей точности, проверьте эту статью . В нем обсуждается, почему модуль не обязательно является хорошим (плохие дистрибутивы, особенно на верхнем уровне), и предоставляет различные варианты.

...