Dani
Dani

Reputation: 11

how to generate random values with uniform intervals in c within a set range

So far I have a function which generates a random integer value within a fixed range (Min, Max) and it seems to work. But how can I make it so that if my range was (0,100), the random values returned is always a multiple of 8? (that is uniform intervals)

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;
}

The same for the code below. How can I make the RANDOM_NUM variable to always be a multiple of 20/3 every time I call it? This one generates a random float value between 0 and 1. (that is uniform intervals)

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

Upvotes: 1

Views: 257

Answers (5)

Weather Vane
Weather Vane

Reputation: 34585

"How can I make the RANDOM_NUM variable to always be a multiple of 20/3 every time I call it?"

I used double in preference to float due to its greater precision, but even so there cannot be a guarantee of an exact multiple, as this program shows. When tested, in some cases the remainder is 0, in the others it is apparently, and absurdly 6.666667, which is 20/3. This is due to the fact that not all numbers can be precisely represented in floating point format.

In decimal point notation the result of the division 1/3 has a recurrent one digit 0.333333~ which in binary point notation has a recurrent 2 digits 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;
}

Program output (random number, remainder):

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

Upvotes: 1

FCo
FCo

Reputation: 505

You could get a random number in the range 0-13 and then multiply your result by 8. It would be in the range [0, 104]. You could do the same thing for 20/3. Assuming you only take integer results, which appears to be true, this would always work.

Upvotes: 0

Konrad
Konrad

Reputation: 529

The fastest solution would be to just set the three lowest bits of the integer to zero: rand &= ~0x07. (Assuming that rand is an integer between 0 and 100.)

Of course that does not apply if you want it to be multiple of a number that is not a power of two and it is hard to read if you're not familiar with bit operations (a comment could not hurt).

Upvotes: 0

VLEFF
VLEFF

Reputation: 533

Assuming that rand is your random integer between 0 and 100 :

rand = rand - (rand % 8);

Upvotes: 0

R Sahu
R Sahu

Reputation: 206577

But how can I make it so that if my range was (0,100), the random values returned is always a multiple of 8?

return ((result % range + Min)/8)*8;

Upvotes: 1

Related Questions