My guess is that this simply produces a random number from a uniform distribution on the interval [0,1]; is this correct?
No. Code may never return 1.0f
nor uniform results.
#define random ((float) rand() / (float)((1 << 31) - 1))
has lots of issues. It is weak code.
Lost of precision: Typical float
has about 24 bit of precision. Converting the result of rand()
, if it exceeds 24 bits, results to a float
which may differ in value from the original due to rounding. This weakens/destroys the uniformity of the random number generation. Different rand()
results will come up with the same answer. See also @Olaf
A fix for this is problematic as OP apparently wants a uniform random number from the set [0, 1/2,147,483,648, 2/2,147,483,648, ... 2,147,483,647/2,147,483,648] which is not possible given the likely precision limits of float
.
The worst, is that (1 << 31)
is undefined behavior UB unless int
is at least 33 bits long. Shifting a 1 into the sign position is UB. C11dr §6.5.7 4.
To avoid UB, use ((1ul << 31) - 1)
.
Yet using the magic number ((1ul << 31) - 1)
is not as robust as basing the fraction on RAND_MAX
.
Further (float) ((1ul << 31) - 1)
may suffer from loss of precision as described above as it forms the value 2147483648.0f
and not the unobtainable 2147483647.0f
. OP's code may never generate a 1.0f
.
I suspect OP really needs a [0..1) result and not [0..1]. Both are below.
// generate a `double` in the range [0 ... 1)
#define random0to_almost1 (rand() / (RAND_MAX + 1.0))
// or
// generate a `double` in the range [0 ... 1]
#define random0to1 (rand() / (RAND_MAX + 0.0))
Note that this suffers like OP's original code should the precision of double
(typical 53 bits) is exceeded by RAND_MAX
needs.
To cope, one mitigating step is to insure RAND_MAX + 1.0
is done exactly. In the extremely common, but not C specified, RAND_MAX
is a power-of-2_minus_1. So RAND_MAX/2 + 1
is an int
and an exact power of 2. Conversion of that int
to double
is certainly exact.
#define random0to_almost1 (rand() / (2.0*(RAND_MAX/2 + 1)))
A float
solution would be
// This value is platform dependent, but very common
// Do not a a highly portable generation method yet.
#define FLT_POWER2_INTEGER_LIMIT (1ul << 24)
#define random0to_almost1 ( \
(rand() % FLT_POWER2_INTEGER_LIMIT) / \
(RAND_MAX % FLT_POWER2_INTEGER_LIMIT + 1.0f) \
)