как генерировать случайные значения с равномерными интервалами в c в пределах заданного диапазона

Пока у меня есть функция, которая генерирует случайное целочисленное значение в фиксированном диапазоне (минимум, максимум), и, похоже, она работает. Но как мне сделать так, чтобы, если мой диапазон был (0,100), возвращаемые случайные значения всегда были кратны 8? (то есть равные интервалы)

int generate_rand(int Min, int Max)
{
// Generates random number between min and max, inclusive.

int range, result, cutoff;

if (Min >= Max)
    return Min; // only one outcome possible, or invalid parameters
range = Max-Min+1;
cutoff = (RAND_MAX / range) * range;

// Rejection method, to be statistically unbiased.
do {
    result = rand();
} while (result >= cutoff);

return result % range + Min;
}

То же самое для кода ниже. Как я могу сделать так, чтобы переменная RANDOM_NUM всегда была кратна 20/3 каждый раз, когда я ее вызываю? Этот генерирует случайное значение с плавающей запятой от 0 до 1. (то есть равномерные интервалы)

 RANDOM_NUM = ((float)rand()/(float)(RAND_MAX+1));

person Dani    schedule 03.02.2015    source источник
comment
От 0 до 100 с кратным 8. Хм, что 12,5 интервалов.   -  person chux - Reinstate Monica    schedule 03.02.2015
comment
Потенциальная проблема с Max-Min+1 заключается в том, что результат может легко переполниться.   -  person chux - Reinstate Monica    schedule 03.02.2015
comment
Примечание. ((float)rand()/(float)(RAND_MAX+1)) может генерировать 0,0, но не 1,0. IOWs [0.0, 1.0) - не совсем значение между 0 и 1.   -  person chux - Reinstate Monica    schedule 03.02.2015


Ответы (5)


Но как мне сделать так, чтобы, если мой диапазон был (0,100), возвращаемые случайные значения всегда были кратны 8?

return ((result % range + Min)/8)*8;
person R Sahu    schedule 03.02.2015

«Как я могу сделать так, чтобы переменная RANDOM_NUM всегда была кратна 20/3 каждый раз, когда я ее вызываю?»

Я использовал double вместо float из-за его большей точности, но даже в этом случае не может быть гарантии точного кратного, как показывает эта программа. При проверке в одних случаях остаток равен 0, в других очевидно, а нелепо 6,666667, что составляет 20/3. Это связано с тем, что не все числа могут быть точно представлены в формате с плавающей запятой.

В записи с десятичной точкой результат деления 1/3 имеет повторяющуюся одну цифру 0.333333~, которая в записи с двоичной точкой имеет повторяющиеся 2 цифры 0.010101~~.

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

#define NUMERATOR   20
#define DENOMINATOR 3

double randnum(int numerator, int denominator) {
    return (double)rand() * (double)numerator / (double)denominator;
}

int main(void) {
    int i;
    double random_num, remainder;
    srand ((unsigned)time(NULL));
    for (i=0; i<10; i++) {
        random_num = randnum(NUMERATOR, DENOMINATOR);
        remainder = fmod(random_num, (double)NUMERATOR / (double)DENOMINATOR);
        printf("%-16f %f\n", random_num, remainder);
    }
    return 0;
}

Вывод программы (случайное число, остаток):

72706.666667     0.000000
209733.333333    0.000000
170686.666667    6.666667
187546.666667    6.666667
121093.333333    6.666667
116660.000000    6.666667
75646.666667     0.000000
64960.000000     6.666667
186653.333333    0.000000
159713.333333    0.000000
person Weather Vane    schedule 03.02.2015

Предполагая, что rand - это ваше случайное целое число от 0 до 100:

ранд = ранд - (ранд % 8);

person VLEFF    schedule 03.02.2015

Самым быстрым решением было бы просто установить три младших бита целого числа равными нулю: rand &= ~0x07. (Предположим, что rand — целое число от 0 до 100.)

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

person Konrad    schedule 03.02.2015

Вы можете получить случайное число в диапазоне 0-13, а затем умножить результат на 8. Он будет в диапазоне [0, 104]. Вы можете сделать то же самое для 20/3. Предполагая, что вы берете только целочисленные результаты, что кажется правдой, это всегда будет работать.

person FCo    schedule 03.02.2015