Description
- Purpose: Fortran implementation of the Philox family of counter-based pseudorandom number generators. Provides stateless, reproducible RNG blocks and utilities for mapping raw 64-bit words into
C_DOUBLEdouble-precision uniform variates. - Intended users: Scientific and HPC Fortran developers who need parallel-friendly, reproducible RNG streams with explicit counter/key control.
This module was produced with the assistance of Microsoft Copilot.
I endeavoured to match against random123 which implements the algorithm in Parallel random numbers: as easy as 1, 2, 3, Salmon, Moraes, Dror & Shaw. The tests use the ISO_C_BINDING features of Fortran to directly compare to the random123 library using the same keys.
No Guarantee is made of correctness or suitability (but it is possibly ok).
Features
- Philox Variants: Implementations for 2x32, 4x32, 2x64, and 4x64 variants (round and logic modules included).
- Stateless Counter/Key API: 256-bit little-endian counter (4×64-bit) plus 128-bit key (2×64-bit) model; no global RNG state.
- Unit-interval Mappings: Multiple mappings with inclusive/exclusive endpoint semantics (
_cc,_co,_oc,_oo) and extraction of the top 53 bits for double precision. - Vectorized Fill: Efficient array-fill routines for bulk sampling.
- Portable Arithmetic Helpers: Multiprecision helpers (
mulhilo32,mulhilo64) and explicit masking/shift logic for bit-exact behavior across platforms. - FPM-ready: Project configured for the Fortran Package Manager (
fpm) withfpm.toml.
Repository Structure
src/— Fortran source files implementing types, constants, rounds, logic, and uniform mapping utilities.app/— Example/demo programs (scalar and vector demos).test/— Tests and reference C headers (random123) — useful for validation (not required to build).
Build
- Requires a Fortran compiler supporting modern Fortran (free source form, ISO C binding).
- Build with
fpm(recommended):
fpm build- Run example/demo executables (auto-executables enabled):
fpm run demo_scalar_uniform
fpm run demo_vector_uniformQuick Start (example)
-
Basic scalar draw in pseudo-code:
- Prepare a 4-element counter and 2-element key (64-bit integers).
- Choose an index
idx(1-based) to select a word from the stream. - Call a mapping function to get a double in [a, b] or (a, b) as required.
-
Example usage pattern (conceptual):
counter = [c1, c2, c3, c4]
key = [k1, k2]
idx = 1
x = philox_uniform_cc(counter, key, idx, a, b) ! [a,b] inclusive endpoints mapping
Worked Fortran Example
This example shows a minimal, copy-paste-ready Fortran program that builds a counter/key, fills an array of 8 doubles using philox_fill_uniform_cc, and prints the results. Save as app/example_fill.f90 or compile alongside the project sources.
program example_fill
use iso_c_binding, only: c_double
use philox, only: philox_fill_uniform_cc, C64
implicit none
integer(kind=C64) :: counter(4)
integer(kind=C64) :: key(2)
real(kind=c_double) :: a, b
real(kind=c_double), allocatable :: x(:)
allocate(x(8))
! Example counter/key (choose deterministic values for reproducibility)
counter = [0_C64, 0_C64, 0_C64, 1_C64]
key = [12345_C64, 67890_C64]
a = 0.0_c_double
b = 1.0_c_double
call philox_fill_uniform_cc(counter, key, 1_c_int64_t, a, b, x)
print *, 'Generated values:'
print *, x
deallocate(x)
end program example_fillWhich produces output (Using ifx 2026.0.0 20260331:
Generated values:
0.270789022090602 0.753506309615939 0.624217905781577
0.548468978471349 0.239322725563122 0.340372667868520
8.239840206884387E-002 0.775633074515794
API Summary
- High-level sampling
philox_uniform_cc,philox_uniform_co,philox_uniform_oc,philox_uniform_oo— scalar samples with endpoint semantics.philox_fill_uniform_cc,philox_fill_uniform_co,philox_fill_uniform_oc,philox_fill_uniform_oo— fill arrays starting at a block index.
- Low-level helpers
word_from_index(counter, key, idx)— produce the 64-bit word for a given 1-based index.counter_add_blocks_4x64(counter, nblocks)— advance a 4×64-bit counter by block counts.philox_u01_*— unit-interval mapping primitives.mulhilo32,mulhilo64— precise multiply-high/low helpers inphilox_common.
Design Notes
- Counter arithmetic is implemented as little-endian 256-bit represented as four 64-bit words; block indexing is 4 words per block.
- Unit-interval mappings use top 53 bits to produce IEEE double-precision values with selectable inclusive/exclusive endpoint behavior.
- Stateless design enables easy, deterministic parallel sampling: partition counters/indices across workers to avoid overlap.
Testing & Validation
- Tests and reference code are available under
test/(includes random123 reference headers and Fortran tests). Use those for correctness verification and platform comparisons. - Tests may be run using
fpm test - TODO: Refactor to use i.e.
test-drive
Use in other Fortran projects
- Use this package in other Fortran projects using
fpmby adding the lines below to yourfpm.toml. Then includeuse_philox
[dependencies]
philox = { git = "https://github.com/RJaBi/Philox_Fortran"}
random123 Sources files
- In order to compile the tests, the source files from random123 are included in
test/random123. The corresponding license is placed in that directory.
Contributing
- Please open issues or pull requests for bug fixes, documentation improvements, or feature requests.
License
- See
fpm.tomlfor license metadata. - MIT