Sazzad Hissain Khan
Sazzad Hissain Khan

Reputation: 40245

Generate random even number in range [m, n]

I was looking for C code to generate a set of random even number in range [start, end]. I tried,

int random = ((start + rand() % (end - start) / 2)) * 2;

This won't work, for example if the range is [0, 4], both 0 & 4 included

int random = (0 + rand() % (4 - 0) / 2) * 2
=> (rand() % 2) * 2
=> 0, 2, ... (never includes 4) but expectation = 0, 2, 4 ...

On the other hands if I use,

int random = ((start + rand() % (end - start) / 2) + 1) * 2;

This won't work, for example,

int random = (0 + (rand() % (4 - 0) / 2) + 1) * 2
=> ((rand() % 4 / 2) + 1) * 2
=> 2, 4,  ... (never includes 0) but expectation = 0, 2, 4 ...

Any clue? how to get rid of this problem?

Upvotes: 0

Views: 4664

Answers (4)

N. Paul
N. Paul

Reputation: 232

I do not trust in the mod operator for random numbers. I prefer

start + ((1 + stop - start) * rand())
         / (1 + RAND_MAX)

which only relies on the distribution of rand() in the interval [0, .. , RAND_MAX] and not on any distribution of rand()%n in the interval [0, .. , n-1].

Note: If you use this expression you should add appropriate casts to avoid multiplication overflow.

Note also ISO/IEC 9899:201x (p.346):

There are no guarantees as to the quality of the random sequence produced and some implementations are known to produce sequences with distressingly non-random low-order bits. Applications with particular requirements should use a generator that is known to be sufficient for their needs.

Upvotes: 1

Paul Ogilvie
Paul Ogilvie

Reputation: 25286

Just and-out the low bit, which makes it even:

n= (rand()%N)&(-2);

and to use a start/stop (a range), the values can be offset:

int n, start= 5, stop= 20+1;
n= ((rand()%(stop-start))+start)&(-2);

The latter calculation generates a random number between 0 and RAND_MAX (this value is library-dependent, but is guaranteed to be at least 32767).

If the stop value must be included in the range of generated numbers, then add 1 to the stop value.

It takes that value modulo the stop value plus the start value, and then adds the start value. The value is now within the range of [start, stop]. As only even numbers are required, the low bit is anded-out because even numbers start at 2.

The anding-out is performed by generating a mask of all 1's, except the lowest bit. As -1 is all 1's (0xFFF...FFFFF), -2 is all 1's except this low bit (0xFFF...FFFFE). Next the bitwise AND operation (&) is perfomed with this mask and the number is now in the range [start,stop]. QED.

Upvotes: 0

klutt
klutt

Reputation: 31409

rand() % x will generate a number in the range [0,x) so if you want the range [0,x] then use rand() % (x+1)

Common notation for ranges is to use [] for inclusive and () for exclusive, so [a,b) would be a range such that a is included but not b.

So in your case, just use (rand() % 3)*2 to get random numbers among {0,2,4}

If you want even numbers in the range [m,n], then use ((m/2) + rand() % ((n-m+2)/2))*2

Upvotes: 2

S.Ptr
S.Ptr

Reputation: 122

You complicated it too much. Since you're using rand() and the modulo operator, I'm assuming that you will not be using this for cryptographic or security purposes, but as a simple even number generator.

The formula I have found for generating a random even number in the range of [0, 2n] is to use

s = (rand() % (n + 1)) * 2

An example code:

#include <stdio.h>

int main() {
    int i, s;
    for(i = 0; i < 100; i++) {
        s = (rand() % 3) * 2;
        printf("%d ", s);
    }
}

And it gave me the following output:

2 2 0 2 4 2 2 0 0 2 4 2 4 2 4 2 0 0 2 2 4 4 0 0 4 4 4 2 2 2 4 0 0 0 4 0 2 2 2 2 0 0 0 4 4 2 4 4 4 0 4 2 2 4 4 0 4 4 2 2 0 0 4 0 4 4 2 0 2 4 0 0 0 0 4 0 4 4 0 4 2 0 0 4 4 0 0 4 4 2 0 0 4 0 2 2 2 0 0 4 0 2 4 2

Best regards!

Upvotes: 3

Related Questions