Draw an exponentially distributed integer with the given mean, in
whatever unit mean is expressed in.
Sampling is a table lookup and two integer multiplies. EXP_TABLE
holds the inverse CDF -ln(1 - k/4096) in Q32.32 fixed point,
generated once by tools/autogen/gen_exp_table.py with 60-digit
decimal arithmetic. Twelve random bits choose a cell, thirty-one more
interpolate linearly inside it, and the result is scaled by mean.
The tail
The top cell runs to infinity and cannot be interpolated into. It is
handled with the memorylessness of the exponential instead: if U is
uniform on the top cell then -ln(1 - U) is distributed as
ln(4096) plus a fresh exponential, so the sampler adds ln(4096)
and draws again. That is exact, and it costs an extra draw with
probability 1/4096.
Capping the top entry at a finite value and interpolating into it –
the obvious alternative – biases the mean by 0.147%. This scheme
leaves 0.002%, and all of that residue is linear interpolation inside
the body cells, not the tail.
mean must be in [0, EXPONENTIAL_MAX_MEAN]. A mean of zero always
returns zero without consuming a draw. Out of range returns zero and,
if err is present, sets ERROR_VALIDATION.
Nodes of different colours represent the following:
Solid arrows point from a procedure to one which it calls. Dashed
arrows point from an interface to procedures which implement that interface.
This could include the module procedures in a generic interface or the
implementation in a submodule of an interface in a parent module.
Where possible, edges connecting nodes are
given different colours to make them easier to distinguish in
large graphs.