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):
// 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:
- Use a different distribution if the moment is non-essential.
- Open an issue / PR — the
feedback_implementation.mdrule 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:
- Generic precision.
statrsisf64-only. We needf32support for GPU + memory-bound bulk sampling. - No-allocation guarantees.
statrsallocates in some cdfs; the bulk samplers in this library cannot afford that. - 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.