28 Jan 2015.

I need to generate a random floating point number.

I know I don't want to do something like rand() % 100 / 100.

A double is just 64-bits, so generate a 64-bit string that looks like

0x3FFn nnnn nnnn nnnn

Where the ns are random hex digits.

As a double, this will be a random number in the range $$[1, 2)$$.

Floating point numbers generated this way have the same distribution as the underlying generator used.

## Why not zero to one?

The range $$[1, 2)$$ uses a single exponent, whereas the range $$[0, 1)$$ spans 1074 different exponents.

Because of the way the floating point encoding works, if I use uniformly distributed random numbers to generate all the bits of the double (the exponent as well as the significand) up to 1.0, I will end up with the same number of samples in the range $$[2^{-1074}, 2^{-1023})$$ as I will in the range $$[0.5, 1.0)$$.

The benefit of using the range $$[1, 2)$$ is that I can use a fixed exponent and generate just the significand, and the distribution stays the same.

## Floating point encoding

IEEE 754-1985 double-precision floating point numbers are encoded as:

• Sign bit.
• 11 bits of exponent.
• 52 bits of significand (sometimes called fraction or mantissa).

Laid out like this:

6  6       5 5         4         3         2         1         0
3210987654321098765432109876543210987654321098765432109876543210
+EEEEEEEEEEEssssssssssssssssssssssssssssssssssssssssssssssssssss
|          |                                                   |
sign bit   exponent                                  significand

The exponent is encoded with an offset:

• A zero value means the exponent is $$2^{-1022}$$ and the number is a "denormal."
• A nonzero value, $$E$$, means the exponent is $$2^{E-1023}$$ and the significand is "normalized."

How to interpret the significand:

• For example, the bit string 1011100000000000000000000000000000000000000000000000.
• This corresponds to the binary number $$1.10111_2$$.
• The leading 1. is implicit in the encoding:
• The exponent is chosen so that the first significant bit is 1.
• Since the first bit is known, we can elide it.
• If it were a denormal number, the significand would be $$0.10111_2$$.
• $$1.10111_2$$ means $$1 + \frac{1}{2} + \frac{1}{8} + \frac{1}{16} + \frac{1}{32}$$.
• Or, in decimal: $$1.718750_{10}$$.

Floating point 0.0 is all zeroes:

+EEEEEEEEEEEssssssssssssssssssssssssssssssssssssssssssssssssssss
0000000000000000000000000000000000000000000000000000000000000000

The next number after zero (i.e. nexttoward(0., 1.)) is:

+EEEEEEEEEEEssssssssssssssssssssssssssssssssssssssssssssssssssss
0000000000000000000000000000000000000000000000000000000000000001
1         2         3         4         5
bit index:  1234567890123456789012345678901234567890123456789012

Here the exponent is $$2^{-1022}$$, the number is denormal, and the significand has the least significant bit set, so the number is:

$$2^{-1022} \times 0.0000000000000000000000000000000000000000000000000000000000000001_2\\ = 2^{-1022} \times 2^{-52}\\ = 2^{-1074}$$

The floating point representation of 1.0 is:

+EEEEEEEEEEEssssssssssssssssssssssssssssssssssssssssssssssssssss
0011111111110000000000000000000000000000000000000000000000000000

The exponent is encoded as $$01111111111_2 = 1023_{10}$$ which corresponds to $$2^0$$.

The significand is $$1.0_2$$ because a normalized number has the implicit bit and the encoded significand is all zeroes after it.