pf_random_exp_at's value computed through a frozen logarithm: identical on every
platform, compiler and flag set, not merely for a given libm.
Same arguments, same range, same two words, same 1 - u convention. The only difference is
which logarithm: parquet_expkey's transform, built from IEEE + - * / with rounding
barriers no compiler may reorder, rather than libm's. The two agree to about 2 ulp, which is
eleven orders of magnitude below the Monte Carlo error of anything that could measure the
difference -- so this is a choice about reproducibility, never about accuracy.
It costs about 3x, measured on machine B (gfortran 15.2.1, -O3 -funroll-loops): the
bulk fill 39.4 ns per value against 11.2, the scalar draw 81.3 against 27.0. The frozen
transform is twelve barriered Horner steps, each a store and a reload, so it neither
vectorises nor pipelines while a libm log does both. Reach for it when a stored result
must reproduce across machines; take the default otherwise.
Not pure, because the frozen transform's rounding barrier is a volatile local and a
pure procedure may not have one. Elemental use still works, but a caller's own pure
procedure and a do concurrent body cannot reach it -- pf_random_exp_at can, and
pf_random_fill_exp_portable works outside the construct.
pf_random_exp_portable_at for an integer(int32) stream index.
impure because exp_key is: the frozen transform's rounding barrier is a volatile
local, and a pure procedure may not have one. Elemental use is unaffected.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(in) | :: | seed |
the stream family's seed |
||
| integer(kind=int32), | intent(in) | :: | i |
stream index; sign-extends, so any value is valid |
||
| integer(kind=int64), | intent(in), | optional | :: | draw |
1-based value index; absent means 1 |
an Exp(1) draw in [0, 36.7368]
pf_random_exp_portable_at for an integer(int64) stream index.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(in) | :: | seed |
the stream family's seed |
||
| integer(kind=int64), | intent(in) | :: | i |
stream index; every value is valid |
||
| integer(kind=int64), | intent(in), | optional | :: | draw |
1-based value index; absent means 1 |
an Exp(1) draw in [0, 36.7368]