Generate Random Numbers Uniformly Over an Entire Range

Generate random numbers uniformly over an entire range

Why rand is a bad idea

Most of the answers you got here make use of the rand function and the modulus operator. That method may not generate numbers uniformly (it depends on the range and the value of RAND_MAX), and is therefore discouraged.

C++11 and generation over a range

With C++11 multiple other options have risen. One of which fits your requirements, for generating a random number in a range, pretty nicely: std::uniform_int_distribution. Here's an example:

const int range_from  = 0;
const int range_to = 10;
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(range_from, range_to);

std::cout << distr(generator) << '\n';

And here's the running example.

Template function may help some:

template<typename T>
T random(T range_from, T range_to) {
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<T> distr(range_from, range_to);
return distr(generator);
}

Other random generators

The <random> header offers innumerable other random number generators with different kind of distributions including Bernoulli, Poisson and normal.

How can I shuffle a container?

The standard provides std::shuffle, which can be used as follows:

std::vector<int> vec = {4, 8, 15, 16, 23, 42};

std::random_device random_dev;
std::mt19937 generator(random_dev());

std::shuffle(vec.begin(), vec.end(), generator);

The algorithm will reorder the elements randomly, with a linear complexity.

Boost.Random

Another alternative, in case you don't have access to a C++11+ compiler, is to use Boost.Random. Its interface is very similar to the C++11 one.

How to generate a number in arbitrary range using random()={0..1} preserving uniformness and density?

If you really want to generate all possible floating point numbers in a given range with uniform numeric density, you need to take into account the floating point format. For each possible value of your binary exponent, you have a different numeric density of codes. A direct generation method will need to deal with this explicitly, and an indirect generation method will still need to take it into account. I will develop a direct method; for the sake of simplicity, the following refers exclusively to IEEE 754 single-precision (32-bit) floating point numbers.

The most difficult case is any interval that includes zero. In that case, to produce an exactly even distribution, you will need to handle every exponent down to the lowest, plus denormalized numbers. As a special case, you will need to split zero into two cases, +0 and -0.

In addition, if you are paying such close attention to the result, you will need to make sure that you are using a good pseudorandom number generator with a large enough state space that you can expect it to hit every value with near-uniform probability. This disqualifies the C/Unix rand() and possibly the*rand48() library functions; you should use something like the Mersenne Twister instead.


The key is to dissect the target interval into subintervals, each of which is covered by different combination of binary exponent and sign: within each subinterval, floating point codes are uniformly distributed.

The first step is to select the appropriate subinterval, with probability proportional to its size. If the interval contains 0, or otherwise covers a large dynamic range, this may potentially require a number of random bits up to the full range of the available exponent.

In particular, for a 32-bit IEEE-754 number, there are 256 possible exponent values. Each exponent governs a range which is half the size of the next greater exponent, except for the denormalized case, which is the same size as the smallest normal exponent region. Zero can be considered the smallest denormalized number; as mentioned above, if the target interval straddles zero, the probability of each of +0 and -0 should perhaps be cut in half, to avoid doubling its weight.

If the subinterval chosen covers the entire region governed by a particular exponent, all that is necessary is to fill the mantissa with random bits (23 bits, for 32-bit IEEE-754 floats). However, if the subinterval does not cover the entire region, you will need to generate a random mantissa that covers only that subinterval.

The simplest way to handle both the initial and secondary random steps may be to round the target interval out to include the entirety of all exponent regions partially covered, then reject and retry numbers that fall outside it. This allows the exponent to be generated with simple power-of-2 probabilities (e.g., by counting the number of leading zeroes in your random bitstream), as well as providing a simple and accurate way of generating a mantissa that covers only part of an exponent interval. (This is also a good way of handling the +/-0 special case.)

As another special case: to avoid inefficient generation for target intervals which are much smaller than the exponent regions they reside in, the "obvious simple" solution will in fact generate fairly uniform numbers for such intervals. If you want exactly uniform distributions, you can generate the sub-interval mantissa by using only enough random bits to cover that sub-interval, while still using the aforementioned rejection method to eliminate values outside the target interval.

Modifying the range of a uniform random number generator

ok I had to think about it for a while but it is actually not that hard. Imagine instead of rand5 you had rand2 which either outputs 0 or 1. You can make rand2 our of rand5 by simply doing

rand2() {
if(rand5() > 2.5) return 1
else return 0
}

now using rand2 multiple times do a tree to get rand7. For example if you start rand7 can be in [1,2,3,4,5,6,7] after a throw of rand2 which gives 0 you now subset to [1,2,3,4] and after another throw or rand2 which is 1 you subset to [3,4] and a final throw of 1 gives the output of rand7 to be 4. In general this tree trick can work to take a rand2 and map to randx where x is any integer.

How to generate uniformly distributed random floating point numbers on entire possible range in matlab

(Why in the name of god and little green apples would you do this in a loop?)

My point is, do it using the capabilities of MATLAB. Learn to use vectors and arrays. Apply operations to an entire array of numbers. This is how a tool like MATLAB shines. Until you do, you might as well be using a lower level language, but without the speed benefits gained from using that lower level tool.

Ok, rant over, so how do we attack this problem?

Generate each number using THREE different random values.

  1. A random sign
  2. A random exponent
  3. A random mantissa

Do it all using vector ops.

numtogenerate = 20000;

% the sign
S = (rand(numtogenerate,1) < 0.5)*2 - 1;

% The exponent
E = floor(rand(numtogenerate,1)*256) - 128;

% The mantissa
M = rand(numtogenerate,1)*2 - 2^-23;

% bring it all together
R = S.*M.*2.^E;

Do they cover the entire range? It seems so.

min(abs(R))
ans =
7.44202895026248e-41

max(R)
ans =
3.17337113940593e+38

min(R)
ans =
-3.3810631675676e+38

Assuming I got the ranges correct for each part, this should essentially generate every possible value in the desired range.

By the way, these are NOT uniformly distributed numbers, at least NOT in the way that term is usually applied in mathematics.



Related Topics



Leave a reply



Submit