{"id":50138710,"url":"https://github.com/vigna/cdflib-rs","last_synced_at":"2026-05-24T00:01:46.190Z","repository":{"id":358690380,"uuid":"1242189192","full_name":"vigna/cdflib-rs","owner":"vigna","description":"A pure Rust port of CDFLIB","archived":false,"fork":false,"pushed_at":"2026-05-18T15:29:29.000Z","size":598,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-18T17:32:04.854Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Fortran","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vigna.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-18T07:48:31.000Z","updated_at":"2026-05-18T15:30:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vigna/cdflib-rs","commit_stats":null,"previous_names":["vigna/cdflib-rs"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/vigna/cdflib-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigna%2Fcdflib-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigna%2Fcdflib-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigna%2Fcdflib-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigna%2Fcdflib-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vigna","download_url":"https://codeload.github.com/vigna/cdflib-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vigna%2Fcdflib-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33416315,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"ssl_error","status_checked_at":"2026-05-23T22:14:43.778Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-24T00:01:45.350Z","updated_at":"2026-05-24T00:01:46.180Z","avatar_url":"https://github.com/vigna.png","language":"Fortran","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CDFLIB\n\nA pure-Rust port of [CDFLIB], the cumulative distribution function library by\nBarry Brown, James Lovato, and Kathy Russell.\n\nThe minimum supported Rust version is 1.71.\n\n## What is CDFLIB?\n\nCDFLIB is a small, venerable numerical library dating to the early 1990s that\ncomputes _cumulative distribution functions_ (CDFs) and their inverses for the\nstandard distributions of frequentist statistics. It is distributed in [Fortran\n90] and in [C]/[C++] (machine-translated from the original [Fortran 77]\nsources). It covers eleven distributions:\n\n| Continuous                        | Discrete          |\n| --------------------------------- | ----------------- |\n| Β                                 | Binomial          |\n| χ², noncentral χ²                 | Negative binomial |\n| F (Fisher–Snedecor), noncentral F | Poisson           |\n| Γ                                 |                   |\n| Normal                            |                   |\n| Student's _t_                     |                   |\n\n## Goals\n\nThe goal of this crate is to provide CDFLIB in pure Rust. The underlying special\nfunctions ([`gamma_inc`], [`beta_inc`], [`error_f`], [`cumnor`], etc.) are\nexposed publicly in a [`cdflib::special`] module for users who want the routines\nwithout the distribution wrappers.\n\nThe API is designed to be ergonomic and idiomatic for Rust users, with [traits]\nrepresenting the common functionality of continuous and discrete distributions,\nand comprehensive error handling via the [`thiserror`] crate.\n\n## Non-goals\n\nExpanding or altering the API beyond what CDFLIB offers is explicitly out of\nscope. This is a machine-translated port of the Fortran 90 code. Other\nlibraries, such as [`statrs`], can use the high-precision functions provided by\nCDFLIB to build more ergonomic APIs. The only exception are convenience\ntextbook one-liners for mean, variance, and so on.\n\n## Notation conventions\n\nThe crate, like CDFLIB itself, uses several interchangeable names for the\nlower- and upper-tail probabilities of a distribution. The synonyms are:\n\n| Concept          | Method   | F90 name | CDFLIB code | Other names                                                            |\n| ---------------- | -------- | -------- | ----------- | ---------------------------------------------------------------------- |\n| Pr[*X* ≤ *x*]    | [`cdf`]  | `cum`    | _P_         | cumulative distribution function, lower-tail probability               |\n| Pr[*X* \u0026gt; *x*] | [`ccdf`] | `ccum`   | _Q_         | complementary cumulative distribution function, upper-tail probability |\n\nThe two are mathematically complementary (_P_ + _Q_ = 1), but the crate computes\nthem independently rather than deriving one from the other by subtraction. This\nis what lets the small tail keep its precision deep into the tails, where `1.0 -\ncdf(x)` would lose digits to cancellation.\n\nThe incomplete-Γ and incomplete-Β routines follow the same convention:\n[`gamma_inc`] returns the pair (_P_, _Q_), [`beta_inc`] returns\n(_Iₓ_(_a_, _b_), 1 − _Iₓ_(_a_, _b_)).\n\n## Why CDFLIB?\n\nMany libraries compute CDFs. CDFLIB is distinguished by two design choices:\n\n### 1. Stays accurate in the tails and at large parameter values\n\nThe numerical heart of CDFLIB is the pair of regularized incomplete-function\nroutines [`gamma_inc`] (≈ [ACM Algorithm 654]) and [`beta_inc`] (≈ [ACM Algorithm\n708]). Both dispatch across five computational regimes depending on the location\nin parameter space (power series, continued fraction, Tricomi–Temme-style asymptotic\nexpansion, near-integer specialization, and ratio-extreme handling) and they\nreturn both the lower and upper tail probabilities directly, without computing\none from the other.\n\nThis is the same algorithm family that underlies SciPy's [incomplete-Γ/Β\nroutines]. It delivers near-machine precision (13–15 digits) deep into the tails\nand at large parameter values, where continued-fraction implementations lose\ndigits to subtractive cancellation or stall on convergence.\n\nThe Rust statistical ecosystem already has [`statrs`], which covers most of\nCDFLIB's distributions. However, at the time of this writing [`statrs`] does\nnot offer parameter searches, [noncentral χ²], or [noncentral _F_], and its\nspecial functions are not as precise as CDFLIB's:\n\n|                                    | True value | CDFLIB   | [`statrs`] |\n| ---------------------------------- | ---------- | -------- | ---------- |\n| _P_(10¹³, 10¹³ + 1)                | ≈ 0.5      | 0.5000   | 0.4926     |\n| _P_(10¹⁵, 10¹⁵ − 1)                | ≈ 0.5      | 0.5000   | 0.00645    |\n| _Iₓ_(10⁸, 4·10⁸) at _x_ = 0.2      | ≈ 0.5      | 0.500009 | 2.262      |\n| _Iₓ_(10¹², 3·10¹²) at _x_ = 0.25   | ≈ 0.5      | 0.500000 | 217.7      |\n| Pr[Poisson(10¹⁵) \u003e 10¹⁵ + 2·√10¹⁵] | ≈ 0.0228   | 0.02275  | 3.97·10⁻⁵  |\n\nNote that these calls are not realistic for a statistician: for everyday\nusage, [`statrs`] and this crate will give the same results. The last example,\nhowever, was the author's motivation for this port—large-scale collision tests\nof pseudorandom number generators are starting to land in that area due\nto more core memory being available, and to improved techniques.\n\n[`rmathlib`], a Rust port of R's special-function library, is another option. It\nis accurate in the body of each distribution, but its asymptotic regime stops\nworking for large _a_ in the regularized incomplete Γ—exactly where χ² tests\nwith many degrees of freedom land. CDFLIB's Tricomi–Temme asymptotic regime (one\nof five branches in [`gamma_inc`]) covers this range cleanly:\n\n|                        | CDFLIB           | [`rmathlib`] |\n| ---------------------- | ---------------- | ------------ |\n| (_P_, _Q_)(500, 500)   | (0.5059, 0.4941) | (NaN, NaN)   |\n| (_P_, _Q_)(5000, 5000) | (0.5019, 0.4981) | (NaN, NaN)   |\n| (_P_, _Q_)(10⁶, 10⁶)   | (0.5001, 0.4999) | (NaN, NaN)   |\n| (_P_, _Q_)(10⁹, 10⁹)   | (0.5000, 0.5000) | (NaN, NaN)   |\n\nThese correspond to χ²(1000), χ²(10⁴), χ²(2·10⁶), and χ²(2·10⁹) at their\nrespective medians, which arise in goodness-of-fit and likelihood-ratio tests on\nlarge samples.\n\n### 2. Solves for any parameter, not just _x_ and _p_\n\nGiven a CDF identity _p_ = _F_(_x_; *θ*₁, *θ*₂, …), most libraries can give you\n_p_ from _x_ (the CDF) or _x_ from _p_ (the inverse CDF, also called the\nquantile function). CDFLIB can additionally compute for any _θᵢ_ when you know\n_p_, _x_, and the other parameters. For example:\n\n- “What standard deviation places probability 0.975 below _x_ = 1.96, given a\n  mean of 0?”\n\n- “What number of trials puts Pr[*X* ≤ 10] at 0.95 in a Binomial with success\n  rate 0.3?”\n\n- “What degrees of freedom for a χ² distribution put 95% of the mass below _x_ =\n  3.84?”\n\n## Examples\n\n### CDFs, complementary CDFs, and inverses\n\n```rust\nuse cdflib::Normal;\nuse cdflib::traits::{Continuous, ContinuousCdf, Mean};\n\nlet n = Normal::try_new(0.0, 1.0)?;\nlet p   = n.cdf(1.96);              // 0.9750021048517796\nlet sf  = n.ccdf(5.0);                // 2.866516e-7, computed directly (not 1 - cdf)\nlet x   = n.inverse_cdf(0.975)?;    // 1.9599639845400538\nlet xs  = n.inverse_ccdf(1e-12)?;     // 7.034484 (accurate deep into the right tail)\nlet d   = n.pdf(0.0);               // 0.3989422804014327\nlet mu  = n.mean();                 // 0.0\n# Ok::\u003c(), cdflib::NormalError\u003e(())\n```\n\n### Parameter searches\n\nGiven _p_ = _F_(_x_; *θ*₁, *θ*₂, …), you can compute any parameter when the\nothers are known. Two practical uses:\n\n```rust\nuse cdflib::{ChiSquared, Poisson};\n\n// Upper 95% confidence bound on λ after observing 3 Poisson events\n// (the Garwood / exact-Poisson interval).\nlet lambda_hi = Poisson::search_lambda(0.05, 0.95, 3)?;\n// 7.7537\n\n// Degrees of freedom that put 95% of a χ² distribution below x = 3.84\n// (recovers df = 1, the classic likelihood-ratio test critical value).\nlet df = ChiSquared::search_df(0.95, 0.05, 3.84)?;\n// 0.9994\n# Ok::\u003c(), Box\u003cdyn std::error::Error\u003e\u003e(())\n```\n\n### Power of a noncentral χ² test\n\n```rust\nuse cdflib::{ChiSquared, ChiSquaredNoncentral};\nuse cdflib::traits::ContinuousCdf;\n\n// Critical value of a χ²(5) test at α = 0.05.\nlet crit = ChiSquared::try_new(5.0)?.inverse_cdf(0.95)?;\n// 11.0705\n\n// Power against a noncentral alternative with ncp = 10.\nlet power = ChiSquaredNoncentral::try_new(5.0, 10.0)?.ccdf(crit);\n// 0.6774\n# Ok::\u003c(), Box\u003cdyn std::error::Error\u003e\u003e(())\n```\n\n### Special functions directly\n\nThese routines are public for users who want the numerics without a distribution wrapper:\n\n```rust\nuse cdflib::special::{cumnor, error_f, gamma_inc};\n\nlet (p, q)      = gamma_inc(2.5, 1.7);   // (0.3614, 0.6386) = (P(2.5,1.7), Q(2.5,1.7))\nlet e           = error_f(0.8);          // 0.7421\nlet (phi, sphi) = cumnor(1.96);          // (0.9750, 0.0250) = (Φ(1.96), 1 - Φ(1.96))\n# let _ = (p, q, e, phi, sphi);\n```\n\nEvery special function with possible failure modes also has a `try_*` form\nthat returns a typed error instead of panicking:\n\n```rust\nuse cdflib::special::{try_gamma_inc, GammaIncError};\n\nlet (p, q) = try_gamma_inc(2.5, 1.7)?;\nassert!(matches!(try_gamma_inc(-1.0, 1.0), Err(GammaIncError::ANegative(_))));\n# let _ = (p, q);\n# Ok::\u003c(), GammaIncError\u003e(())\n```\n\n### Beautiful names\n\nRust allows you to rename the functions:\n\n```rust\nuse cdflib::special::{beta as Β, cumnor as Φ, gamma as Γ, psi as ψ};\n\nlet x = Γ(2.5);            // Γ(5/2) = (3/2)·√π / 2 ≈ 1.3293\nlet y = Β(2.0, 3.0);       // Β(2, 3) = 1/12\nlet (p, _) = Φ(1.96);      // Φ(1.96) ≈ 0.975\nlet γ = -ψ(1.0);           // ψ(1) = −γ (Euler–Mascheroni)\n# let _ = (x, y, p, γ);\n```\n\n## Fidelity to CDFLIB\n\nThe port is semantically faithful: every algorithmic decision, polynomial\ncoefficient, branch threshold, and truncation depth matches `cdflib.f90` to the\ndigit. The intentional structural divergences are:\n\n- There is no silent error returned as a special value, or errors returned as an\n  integer index. All functions returning errors have a `try_` prefix and return\n  a `Result` with a documented error type. The error types are designed to be as\n  specific as possible about the nature of the error.\n- All functions with a `try_` prefix have an infallible variant that panics on\n  errors, and is documented as such.\n- The Fortran routine `gamma_user` is exposed under the Rust name [`gamma`]. The\n  Fortran name encodes a Fortran-2008 workaround (the language added a `gamma`\n  intrinsic, so the routine had to be renamed to avoid the collision). Rust has\n  no such conflict, so the routine takes the bare family name, mirroring\n  [`beta`].\n- `error_fc(ind, x)` (which multiplexes plain and exponentially-scaled output\n  via an integer flag) is split into two Rust functions, [`error_fc`] and\n  [`error_fc_scaled`]. Same numerics, no flag argument.\n- The Fortran `cum*` and `cdf*` method families are folded into the\n  corresponding distribution module's [`cdf`] / [`ccdf`] / [`inverse_cdf`] /\n  [`inverse_ccdf`] / `search_*` methods rather than exposed as bare functions.\n- `dinvr` and `dzror` (the reverse-communication root finders) live as internal\n  state machines in `crate::search`. They are not part of the public surface.\n- The search setup constants (`abs_step`, `rel_step`, `stp_mul`, `abs_tol`,\n  `rel_tol`) that the Fortran `cdf*` routines declare locally are centralized in\n  `src/search/mod.rs`; the one routine that needs a different absolute tolerance\n  (`cdfchn`) uses an explicit `search_monotone_with_atol` call.\n\nThe lower-level CDFLIB-style helpers ([`algdiv`], [`bcorr`], [`gam1`], [`rlog`],\netc.) live in [`cdflib::special::internal`] so the user-facing\n[`cdflib::special`] surface stays focused on the routines a statistical user is\nlikely to call. Each CDFLIB algorithmic routine can be found under its original\nname, modulo the renames and splits enumerated above. The machine-constant\nutilities (`ipmpar`, `dpmpar`, `exparg`) and the `ftnstop` fatal-error sink are\nnot ported: the constants live as Rust module-level values, and error reporting\ngoes through the `try_*`/`Result` pairs described above.\n\n## Testing\n\nReference values for the test suite are pre-generated from the bundled Fortran 90\nsources (`tests/regenerate/`) and committed as CSV fixtures under `tests/data/`.\n`cargo test` reads the CSVs directly; CSV fixtures can be regenerated using the\nshell scripts in `tests/regenerate/` if desired; you will need a Fortran 90\ncompiler.\n\nThe code has been extensively tested against the original Fortran 90 and C\nsources. In the process, we found [serious bugs in `rmathlib`] and a bug in the\n[Fortran 90 version of the library] that has remained undetected for 25 years: a\ncoefficient for the computation of the error function had been transcribed from\nthe [original Fortran 77 code] with a wrong exponent (the [C]/[C++] version are\nunaffected).\n\n[CDFLIB]: https://people.sc.fsu.edu/~jburkardt/cpp_src/cdflib/cdflib.html\n[ACM Algorithm 654]: https://dl.acm.org/doi/10.1145/29380.214348\n[ACM Algorithm 708]: https://dl.acm.org/doi/10.1145/131766.131776\n[`gamma_inc`]: https://docs.rs/cdflib/latest/cdflib/special/fn.gamma_inc.html\n[`beta_inc`]: https://docs.rs/cdflib/latest/cdflib/special/fn.beta_inc.html\n[`error_f`]: https://docs.rs/cdflib/latest/cdflib/special/fn.error_f.html\n[`cumnor`]: https://docs.rs/cdflib/latest/cdflib/special/fn.cumnor.html\n[`cdflib::special`]: https://docs.rs/cdflib/latest/cdflib/special/index.html\n[`statrs`]: https://crates.io/crates/statrs\n[`rmathlib`]: https://crates.io/crates/rmathlib\n[`thiserror`]: https://crates.io/crates/thiserror\n[incomplete-Γ/Β routines]: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.gammainc.html\n[serious bugs in `rmathlib`]: https://github.com/tla-org/rmathlib/issues/38\n[original Fortran 77 code]: https://dl.acm.org/doi/10.1145/131766.131776#supplementary-materials\n[traits]: https://docs.rs/cdflib/latest/cdflib/traits/index.html\n[`cdflib::special::internal`]: https://docs.rs/cdflib/latest/cdflib/special/internal/index.html\n[`gamma`]: https://docs.rs/cdflib/latest/cdflib/special/fn.gamma.html\n[`beta`]: https://docs.rs/cdflib/latest/cdflib/special/fn.beta.html\n[`error_fc`]: https://docs.rs/cdflib/latest/cdflib/special/fn.error_fc.html\n[`error_fc_scaled`]: https://docs.rs/cdflib/latest/cdflib/special/fn.error_fc_scaled.html\n[`algdiv`]: https://docs.rs/cdflib/latest/cdflib/special/internal/fn.algdiv.html\n[`bcorr`]: https://docs.rs/cdflib/latest/cdflib/special/internal/fn.bcorr.html\n[`gam1`]: https://docs.rs/cdflib/latest/cdflib/special/internal/fn.gam1.html\n[`rlog`]: https://docs.rs/cdflib/latest/cdflib/special/internal/fn.rlog.html\n[noncentral χ²]: https://docs.rs/cdflib/latest/cdflib/struct.ChiSquaredNoncentral.html\n[noncentral _F_]: https://docs.rs/cdflib/latest/cdflib/struct.FisherSnedecorNoncentral.html\n[Fortran 90 version of the library]: https://people.sc.fsu.edu/~jburkardt/f_src/cdflib/cdflib.html\n[original Fortran 77 code]: https://people.sc.fsu.edu/~jburkardt/f77_src/cdflib/cdflib.html\n[`cdf`]: https://docs.rs/cdflib/latest/cdflib/traits/trait.ContinuousCdf.html#tymethod.cdf\n[`ccdf`]: https://docs.rs/cdflib/latest/cdflib/traits/trait.ContinuousCdf.html#tymethod.ccdf\n[`inverse_cdf`]: https://docs.rs/cdflib/latest/cdflib/traits/trait.ContinuousCdf.html#tymethod.inverse_cdf\n[`inverse_ccdf`]: https://docs.rs/cdflib/latest/cdflib/traits/trait.ContinuousCdf.html#tymethod.inverse_ccdf\n[Fortran 90]: https://people.sc.fsu.edu/~jburkardt/f_src/cdflib/cdflib.html\n[Fortran 77]: https://people.sc.fsu.edu/~jburkardt/f77_src/cdflib/cdflib.html\n[C]: https://people.sc.fsu.edu/~jburkardt/c_src/cdflib/cdflib.html\n[C++]: https://people.sc.fsu.edu/~jburkardt/cpp_src/cdflib/cdflib.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvigna%2Fcdflib-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvigna%2Fcdflib-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvigna%2Fcdflib-rs/lists"}