Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

std.stat

import std.stat supplies descriptive statistics over &list[f64] and normal, uniform and exponential distributions. It is checked Plenty code; there is no native statistics dependency or global random state.

import std.random
import std.stat
from std.stat import StatError

def main() -> Result[(), AllocError | IoError | StatError]:
    values = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]?
    print(std.stat.mean(&values)?, std.stat.median(&values)?, std.stat.pstdev(&values)?)?
    print(std.stat.quantiles(&values)?)?
    scores = std.stat.normal(100.0, 15.0)?
    print(scores.cdf(100.0)?, scores.inverse_cdf(0.5)?)?
    mut rng = std.random.seeded(42u64)
    draw = scores.sample(&mut rng)?
    print(draw > 0.0 and draw < 200.0)?
    Ok(())
5.0 4.5 2.0
[4.0, 4.5, 5.5]
0.5 100.0
True

Observations

All observations must be finite. Empty data returns StatError.Empty, and NaN or infinity returns NonFinite. Convert integer observations explicitly to f64; integers beyond 2^53 may lose precision during conversion.

FunctionMeaningAllocation
mean(values)Arithmetic meanNone
pvariance(values), pstdev(values)Population variance/deviation, denominator nNone
variance(values), stdev(values)Sample variance/deviation, denominator n-1; needs two observationsNone
median(values)Middle value, or midpoint of the middle pairCopy and sort
quantile(values, p)Inclusive linear interpolation, 0 <= p <= 1Copy and sort
quantiles(values, n: Positive[i64] = 4)The n-1 cuts at i/nCopy/sort plus output list

Quantiles use Hyndman–Fan type 7: interpolate at sorted index p*(length-1). This corresponds to Python’s statistics.quantiles(method="inclusive"), not its default exclusive method. A singleton yields its one value at every probability. n=1 produces an empty list after validating the data. The original list is never mutated. Sorting takes O(n log n) time and O(n) additional space; the other functions take O(n) time and constant space.

Mean uses scaled, compensated summation. Deviation uses a corrected two-pass calculation with scaled differences. These avoid many overflow/cancellation problems of summing raw values or squares, but are still approximate f64 calculations, not exact arithmetic. Underflow may round to zero. An unrepresentable result is Overflow; deviation can succeed when variance overflows. A one-element sample returns InsufficientData.

Distributions

Constructors validate parameters and return Result[Distribution, StatError]:

ConstructorParameters
normal(mean=0.0, sigma=1.0)Finite mean and strictly positive finite standard deviation
uniform(low=0.0, high=1.0)Finite ordered bounds; width and reciprocal width must be representable
exponential(rate=1.0)Strictly positive finite rate

All three provide pdf(x), cdf(x), and inverse_cdf(p), returning Result[f64, StatError]. NaN observations are rejected; infinite observations have their usual limiting densities and probabilities. Probabilities must be finite and in [0,1]. Normal inverse endpoints are negative/positive infinity; exponential’s upper endpoint is infinity. Uniform inverse endpoints are its bounds, and its density includes both bounds (irrelevant to integrals). Parameters are private and cannot be changed after construction.

Normal tails use a central power series and Laplace’s continued fraction for the Mills ratio; inversion bisects the smaller tail. Regression checks cover central values, tails through probability 1e-100 and inverse round trips with a 2e-13 relative tolerance. This is a tested tolerance, not a correctly-rounded guarantee for every f64. Upper-tail CDFs eventually round to one; lower tails underflow near 39 standard deviations. Inversion uses 64 iterations of the bounded tail evaluation and is intended for ordinary statistical use, not high-throughput vector analysis. Exponential uses expm1/log1p to retain small-probability precision. Finite-result arithmetic overflow is reported.

Sampling and reproducibility

Pass a mutable std.random.Rng to sample. Uniform returns f64; normal and exponential return Result[f64, StatError] because the transformed value can overflow. An error leaves the generator unchanged. All constructors, queries and sampling operations allocate nothing.

DistributionDraw policy
UniformOne next_f64() draw u; interpolate between bounds
ExponentialOne draw u; -log1p(-u)/rate
NormalTwo draws u,v; Box–Muller mean + sigma*sqrt(-2*log1p(-u))*cos(tau*v); no cached partner

The draw counts and these transformations are version-stable; adding distributions does not change any std.random sequence. Transcendental functions follow the platform math implementation, so samples are reproducible within the same math environment, not promised bit-identical across platforms or libm updates. Rounding can put a uniform sample exactly at the upper bound. No sampling function reads the clock, OS entropy, or a global generator.

Errors and scope

StatError has Empty, InsufficientData, NonFinite, Domain, Overflow and Allocation(AllocError). Invalid distribution parameters and probabilities are Domain; failures to allocate sorted/output lists retain the original allocation cause, including CapacityOverflow for an unrepresentable quantile output allocation. Validated list lengths, positive quantile counts and fixed iteration budgets bound internal integer arithmetic; no primitive arithmetic errors are added to the public contracts. These operations have no hidden retry.

This module does not provide hypothesis tests, regression, weighted statistics, discrete distributions, arbitrary precision or dataframe aggregation. Use std.dataframe for bulk analytical queries.

Algorithm references: Python statistics, statrs distributions, and Lee’s analysis of the Laplace fraction. See the statistics tutorial for examples.

Acknowledgements