Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meaning of ((float) rand() / (float)((1 << 31) - 1))

Tags:

c

random

I'm trying to understand a C program which includes a .h file with the line

#define random                  ((float) rand() / (float)((1 << 31) - 1))

The C program also includes <math.h>.

My guess is that this simply produces a random number from a uniform distribution on the interval [0,1]; is this correct?

like image 452
Kurt Peek Avatar asked Aug 04 '16 15:08

Kurt Peek


2 Answers

Ostensibly yes. But it's wrong in two principal ways:

  1. Use RAND_MAX instead. That's what it's there for. It might be much smaller than 1 << 31 - 1.

  2. 1 << 31 will give you undefined behaviour on a platform with a 32 bit int or less, which is remarkably common. Don't do that!

Note that if you don't want to ever recover the value 1, (as is often the case), then use RAND_MAX + 1.0 on the denominator. The 1.0 forces evaluation in floating point: you run the risk of overflowing an integral type if you write RAND_MAX + 1.

like image 109
Fitzwilliam Bennet-Darcy Avatar answered Oct 19 '22 15:10

Fitzwilliam Bennet-Darcy


The rand function returns a value between 0 and RAND_MAX. This program is assuming that RAND_MAX is 2^31 - 1 and is dividing the result by that number.

So yes, if the above assumption is true, then this macro gives a number from [0,1]. It is not so much a uniform random distribution, but rather a "pseudo-random" value.

At least that's what it's supposed to do. This expression (1 << 31) invokes undefined behavior (assuming int is 32-bit or less) because the the constant 1 has type int and left-shifting by 31 puts it outside the range of int. In practice, if two's complement representation is used, some compilers will allow this shift and then the subsequent -1 will put it back in range, but that can't be depended on.

This undefined behavior can be avoided by using (1U << 31), which makes the constant 1 have type unsigned int so that the shift it within range. A better option is to forget the shift and subtract and just use 0x7fffffff.

But for maximum portability, it should be defined as follows:

#define random ((float)rand() / RAND_MAX)

But there's still a problem. A float typically has a 23 bit mantissa. If rand returns a 32 bit value, you won't get a good distribution of numbers. Better use use double, which has a 52 bit mantissa:

#define random ((double)rand() / RAND_MAX)
like image 29
dbush Avatar answered Oct 19 '22 17:10

dbush