pf_random_exp_portable_at Interface

public interface pf_random_exp_portable_at

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.


Module Procedures

private impure elemental function pf_random_exp_portable_at_i32(seed, i, draw) result(r)

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.

Arguments

Type IntentOptional 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

Return Value real(kind=real64)

an Exp(1) draw in [0, 36.7368]

private impure elemental function pf_random_exp_portable_at_i64(seed, i, draw) result(r)

pf_random_exp_portable_at for an integer(int64) stream index.

Arguments

Type IntentOptional 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

Return Value real(kind=real64)

an Exp(1) draw in [0, 36.7368]