stochastic-rs
Concepts

DistributionExt

Closed-form pdf, cdf, characteristic function, and moments for every distribution — 18 of 19 closed-form, with five named unimplemented moments.

DistributionExt

Closed-form analytics for every distribution that has them.

DistributionExt is f64-only (not generic over T), and every method defaults to a type_name-annotated unimplemented!() — a distribution overrides only the methods it has a closed form for:

// Signature sketch. Every method below is a *provided* method whose default
// body is a `type_name`-annotated `unimplemented!()`; the bodies are elided
// here. See `stochastic-rs-distributions/src/traits/distribution.rs`.
pub trait DistributionExt {
  fn characteristic_function(&self, t: f64) -> Complex64;
  fn pdf(&self, x: f64) -> f64;
  fn cdf(&self, x: f64) -> f64;
  fn inv_cdf(&self, p: f64) -> f64;
  fn mean(&self) -> f64;
  fn median(&self) -> f64;
  fn mode(&self) -> f64;
  fn variance(&self) -> f64;
  fn skewness(&self) -> f64;
  fn kurtosis(&self) -> f64;
  fn entropy(&self) -> f64;
  fn moment_generating_function(&self, t: f64) -> f64;
}

Coverage

18 / 19 distributions implement closed-form pdf, cdf, characteristic function, mean, and variance. The exception is ComplexDistribution, which is a wrapper used by Fourier-domain pricers and intentionally opaque.

For higher-order moments, 5 named distributions carry unimplemented! for skewness and / or kurtosis — those are documented on each distribution's reference page. The remaining 14 ship full closed-form skewness and excess kurtosis.

Default behaviour: panic, never zero

Project rule: an unimplemented moment panics with a helpful message including the type name, never silently returns 0. This was a deliberate choice after a v1.x bug where a silent-zero kurtosis caused a downstream calibration to converge on garbage. Reproduced below (the crate's own equivalent helper is private):

tests/doctest_concepts_unimplemented_moment.rs
// docs: concepts/distribution-ext#default-behaviour-panic-never-zero
//! Backs the "default behaviour: panic, never zero" example on the
//! DistributionExt concept page. Reproduces the doc's helper verbatim
//! (the crate's own equivalent is private) and proves it panics with the
//! documented message instead of silently returning a number.

fn unimplemented_moment<T>() -> ! {
  let name = std::any::type_name::<T>();
  unimplemented!("moment not implemented for {name}")
}

#[test]
#[should_panic(expected = "moment not implemented for f64")]
fn unimplemented_moment_panics_with_type_name() {
  unimplemented_moment::<f64>();
}

If you hit such a panic, you have two options:

  1. Use a different distribution if the moment is non-essential.
  2. Open an issue / PR — the feedback_implementation.md rule says we follow papers exactly, so closed forms get added with a citation.

Why no statrs::distribution::*

The library deliberately writes closed forms from scratch in stochastic-rs-distributions, never delegating to statrs. Reasons:

  1. Generic precision. statrs is f64-only. We need f32 support for GPU + memory-bound bulk sampling.
  2. No-allocation guarantees. statrs allocates in some cdfs; the bulk samplers in this library cannot afford that.
  3. Audit trail. Every formula in this crate is anchored to a paper citation, with a comparison test against the paper's numerical tables. statrs's implementations are competent but lack that audit trail.

See the per-distribution pages under Distributions for the formulas, tests, and references.

On this page