pic_random_dist_real Module

Distributions that return real(dp).

Read this before using these in simulation state

These call log, sqrt and cos. Those are libm functions, and libm is not one function: GNU, Intel, NVIDIA, LLVM and LFortran do not agree to the last bit on any of them, and nothing obliges them to. Two runs of the same code with the same seed on two compilers will therefore produce different values here.

That is fine for a histogram, a plot, a convergence study or a back-of-the-envelope estimate. It is not fine for anything that has to be compared across runs or across machines – a checkpoint digest, a determinism log, a bisected divergence. For those, use pic_random_dist, whose every routine is integer-only and pinned by tests.

The two tiers are separate modules precisely so that this is a decision rather than an accident: code that never names this module cannot reach a non-reproducible deviate.

Quick start

use pic_rng, only: splitmix64_t
use pic_random_dist_real, only: next_exponential_dp, next_normal_dp

type(splitmix64_t) :: gen
call gen%seed(20250914_int64)

wait = next_exponential_dp(gen, 4.0_dp)          ! mean 4
noise = next_normal_dp(gen, 0.0_dp, 1.0_dp)      ! standard normal

Uses

  • module~~pic_random_dist_real~~UsesGraph module~pic_random_dist_real pic_random_dist_real module~pic_rng pic_rng module~pic_random_dist_real->module~pic_rng module~pic_types pic_types module~pic_random_dist_real->module~pic_types module~pic_rng->module~pic_types module~pic_error pic_error module~pic_rng->module~pic_error module~pic_uint64 pic_uint64 module~pic_rng->module~pic_uint64 iso_c_binding iso_c_binding module~pic_types->iso_c_binding iso_fortran_env iso_fortran_env module~pic_types->iso_fortran_env module~pic_error->module~pic_types module~pic_global_definitions pic_global_definitions module~pic_error->module~pic_global_definitions module~pic_uint64->module~pic_types module~pic_global_definitions->module~pic_types

Variables

Type Visibility Attributes Name Initial
real(kind=dp), private, parameter :: TWO_PI = 6.283185307179586476925286766559_dp

2*pi to more digits than real(dp) can hold, so the nearest representable value is selected rather than a rounded decimal.


Interfaces

public interface next_exponential_dp

Draw an exponential deviate with the given mean.

Inverse transform: -mean * log(u) with u uniform in (0, 1]. The uniform is taken as 1 - next_real_dp(gen) rather than next_real_dp(gen) because the latter can return exactly zero, and log(0) is minus infinity. Subtracting from one moves the excluded endpoint to the other side, where it is harmless.

A negative mean is not rejected; it simply mirrors the distribution about zero, which is occasionally what a caller wants.

  • private function splitmix64_next_exponential_dp(gen, mean) result(r)

    Exponential deviate from a SplitMix64 generator.

    Arguments

    Type IntentOptional Attributes Name
    type(splitmix64_t), intent(inout) :: gen

    Generator, advanced by one draw.

    real(kind=dp), intent(in) :: mean

    Mean of the distribution.

    Return Value real(kind=dp)

  • private function pcg32_next_exponential_dp(gen, mean) result(r)

    Exponential deviate from a PCG32 generator.

    Arguments

    Type IntentOptional Attributes Name
    type(pcg32_t), intent(inout) :: gen

    Generator, advanced by one draw.

    real(kind=dp), intent(in) :: mean

    Mean of the distribution.

    Return Value real(kind=dp)

public interface next_normal_dp

Draw a normal deviate with mean mu and standard deviation sigma.

Box-Muller. The transform naturally yields two independent deviates per pair of uniforms, and the usual implementation caches the second for the next call. This one discards it.

That halves the throughput and is deliberate. A cache makes the generator state depend on whether the call count is odd or even, so two runs that draw the same number of normals but interleave them differently with other draws diverge. Without it, the generator’s position is a plain function of how many times it has been asked for anything, which is far easier to reason about – and it keeps this function pure in spirit: no hidden state between calls.

  • private function splitmix64_next_normal_dp(gen, mu, sigma) result(r)

    Normal deviate from a SplitMix64 generator.

    Arguments

    Type IntentOptional Attributes Name
    type(splitmix64_t), intent(inout) :: gen

    Generator, advanced by exactly two draws.

    real(kind=dp), intent(in) :: mu

    Mean.

    real(kind=dp), intent(in) :: sigma

    Standard deviation.

    Return Value real(kind=dp)

  • private function pcg32_next_normal_dp(gen, mu, sigma) result(r)

    Normal deviate from a PCG32 generator.

    Arguments

    Type IntentOptional Attributes Name
    type(pcg32_t), intent(inout) :: gen

    Generator, advanced by exactly two draws.

    real(kind=dp), intent(in) :: mu

    Mean.

    real(kind=dp), intent(in) :: sigma

    Standard deviation.

    Return Value real(kind=dp)


Functions

private function pcg32_next_exponential_dp(gen, mean) result(r)

Exponential deviate from a PCG32 generator.

Arguments

Type IntentOptional Attributes Name
type(pcg32_t), intent(inout) :: gen

Generator, advanced by one draw.

real(kind=dp), intent(in) :: mean

Mean of the distribution.

Return Value real(kind=dp)

private function pcg32_next_normal_dp(gen, mu, sigma) result(r)

Normal deviate from a PCG32 generator.

Arguments

Type IntentOptional Attributes Name
type(pcg32_t), intent(inout) :: gen

Generator, advanced by exactly two draws.

real(kind=dp), intent(in) :: mu

Mean.

real(kind=dp), intent(in) :: sigma

Standard deviation.

Return Value real(kind=dp)

private function splitmix64_next_exponential_dp(gen, mean) result(r)

Exponential deviate from a SplitMix64 generator.

Arguments

Type IntentOptional Attributes Name
type(splitmix64_t), intent(inout) :: gen

Generator, advanced by one draw.

real(kind=dp), intent(in) :: mean

Mean of the distribution.

Return Value real(kind=dp)

private function splitmix64_next_normal_dp(gen, mu, sigma) result(r)

Normal deviate from a SplitMix64 generator.

Arguments

Type IntentOptional Attributes Name
type(splitmix64_t), intent(inout) :: gen

Generator, advanced by exactly two draws.

real(kind=dp), intent(in) :: mu

Mean.

real(kind=dp), intent(in) :: sigma

Standard deviation.

Return Value real(kind=dp)