{"id":26798103,"url":"https://github.com/olson-sean-k/decorum","last_synced_at":"2025-05-16T12:01:45.929Z","repository":{"id":47211659,"uuid":"108192756","full_name":"olson-sean-k/decorum","owner":"olson-sean-k","description":"Making floating-point behave.","archived":false,"fork":false,"pushed_at":"2024-11-22T01:46:29.000Z","size":320,"stargazers_count":79,"open_issues_count":7,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-12T21:25:41.320Z","etag":null,"topics":["equivalence","floating-point","hashing","ieee-754","library","ordering","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/olson-sean-k.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2017-10-24T22:56:23.000Z","updated_at":"2025-01-29T21:10:11.000Z","dependencies_parsed_at":"2024-06-19T19:08:14.145Z","dependency_job_id":"c36b4c9a-4eb0-41c4-ade8-4f5e24ba3c60","html_url":"https://github.com/olson-sean-k/decorum","commit_stats":{"total_commits":212,"total_committers":3,"mean_commits":70.66666666666667,"dds":0.009433962264150941,"last_synced_commit":"7730ac2470c1309fd5fd2ce06d04b3101af0e4ae"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olson-sean-k%2Fdecorum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olson-sean-k%2Fdecorum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olson-sean-k%2Fdecorum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olson-sean-k%2Fdecorum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/olson-sean-k","download_url":"https://codeload.github.com/olson-sean-k/decorum/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254527071,"owners_count":22085917,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["equivalence","floating-point","hashing","ieee-754","library","ordering","rust"],"created_at":"2025-03-29T19:17:06.651Z","updated_at":"2025-05-16T12:01:45.873Z","avatar_url":"https://github.com/olson-sean-k.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n    \u003cimg alt=\"Decorum\" src=\"https://raw.githubusercontent.com/olson-sean-k/decorum/master/doc/decorum.svg?sanitize=true\" width=\"320\"/\u003e\n\u003c/div\u003e\n\u003cbr/\u003e\n\n**Decorum** is a Rust library that provides total ordering, equivalence,\nhashing, constraints, error handling, and more for IEEE 754 floating-point\nrepresentations. Decorum does **not** require the `std` nor `alloc` libraries,\nthough they are necessary for some features.\n\n[![GitHub](https://img.shields.io/badge/GitHub-olson--sean--k/decorum-8da0cb?logo=github\u0026style=for-the-badge)](https://github.com/olson-sean-k/decorum)\n[![docs.rs](https://img.shields.io/badge/docs.rs-decorum-66c2a5?logo=rust\u0026style=for-the-badge)](https://docs.rs/decorum)\n[![crates.io](https://img.shields.io/crates/v/decorum.svg?logo=rust\u0026style=for-the-badge)](https://crates.io/crates/decorum)\n\n## Basic Usage\n\nPanic when a `NaN` is encountered:\n\n```rust\nuse decorum::NotNan;\n\nlet x = NotNan::\u003cf64\u003e::assert(0.0);\nlet y = NotNan::\u003cf64\u003e::assert(0.0);\nlet z = x / y; // Panics.\n```\n\nHash totally ordered IEEE 754 floating-point representations:\n\n```rust\nuse decorum::real::UnaryRealFunction;\nuse decorum::Real;\nuse std::collections::HashMap;\n\nlet key = Real::\u003cf64\u003e::PI;\nlet mut xs: HashMap\u003c_, _\u003e = [(key, \"pi\")].into_iter().collect();\n```\n\nConfigure the behavior of an IEEE 754 floating-point representation:\n\n```rust\npub mod real {\n    use decorum::constraint::IsReal;\n    use decorum::divergence::{AsResult, OrError};\n    use decorum::proxy::{Constrained, OutputFor};\n\n    // A 64-bit floating-point type that must represent a real number and returns\n    // `Result`s from fallible operations.\n    pub type Real = Constrained\u003cf64, IsReal\u003cOrError\u003cAsResult\u003e\u003e\u003e;\n    pub type Result = OutputFor\u003cReal\u003e;\n}\n\nuse real::Real;\n\npub fn f(x: Real) -\u003e real::Result { ... }\n\nlet x = Real::assert(0.0);\nlet y = Real::assert(0.0);\nlet z = (x / y)?;\n```\n\n## Proxy Types\n\nThe primary API of Decorum is its `Constrained` types, which transparently wrap\nprimitive IEEE 754 floating-point types and configure their behavior.\n`Constrained`\ntypes support many numeric features and operations and integrate with the\n[`num-traits`] crate and others when [Cargo features](#cargo-features) are\nenabled. Depending on its configuration, a proxy can be used as a drop-in\nreplacement for primitive floating-point types.\n\nThe following `Constrained` behaviors can be configured:\n\n1. the allowed subset of IEEE 754 floating-point values\n1. the output type of fallibe operations (that may produce non-member values\n   w.r.t. a subset)\n1. what happens when an error occurs (i.e., return an error value or panic)\n\nNote that the output type of fallible operations and the error behavior are\nindependent. A `Constrained` type may return a `Result` and yet panic if an error\noccurs, which can be useful for conditional compilation and builds wherein\n**behavior** changes but types do not. The behavior of a `Constrained` type is\nconfigured using two mechanisms: _constraints_ and _divergence_.\n\n```rust\nuse decorum::constraint::IsReal;\nuse decorum::divergence::OrPanic;\nuse decorum::proxy::Constrained;\n\n// `Real` must represent a real number and otherwise panics.\npub type Real = Constrained\u003cf64, IsReal\u003cOrPanic\u003e\u003e;\n```\n\nConstraints specify a subset of floating-point values that a proxy may\nrepresent. IEEE 754 floating-point values are divided into three such subsets:\n\n| Subset        | Example Member |\n|---------------|----------------|\n| real numbers  | `3.1459`       |\n| infinities    | `+INF`         |\n| not-a-numbers | `NaN`          |\n\nConstraints can be used to strictly represent real numbers, extended reals, or\ncomplete but totally ordered IEEE 754 types (i.e., no constraints). Available\nconstraints are summarized below:\n\n| Constraint       | Members                                 | Fallible  |\n|------------------|-----------------------------------------|-----------|\n| `IsFloat`        | real numbers, infinities, not-a-numbers | no        |\n| `IsExtendedReal` | real numbers, infinities                | yes       |\n| `IsReal`         | real numbers                            | yes       |\n\n`IsFloat` supports all IEEE 754 floating-point values and so applies no\nconstraint at all. As such, it has no fallible operations w.r.t. the constraint\nand does not accept a divergence.\n\nMany operations on members of these subsets may produce values from other\nsubsets that are illegal w.r.t. constraints, such as the addition of two real\nnumbers resulting in `+INF`. A _divergence type_ determines both the behavior\nwhen an illegal value is encountered as well as the output type of such fallible\noperations.\n\n| Divergence | OK       | Error     | Default Output Kind |\n|------------|----------|-----------|---------------------|\n| `OrPanic`  | continue | **panic** | `AsSelf`            |\n| `OrError`  | continue | break     | `AsExpression`      |\n\nIn the above table, _continue_ refers to returning a **non**-error value while\n_break_ refers to returning an error value. If an illegal value is encountered,\nthen **the `OrPanic` divergence panics** while the `OrError` divergence\nconstructs a value that encodes the error. The output type of fallible\noperations is determined by an _output kind_:\n\n| Output Kind    | Type                  | Continue        | Break              |\n|----------------|-----------------------|-----------------|--------------------|\n| `AsSelf`       | `Self`                | `self`          |                    |\n| `AsOption`     | `Option\u003cSelf\u003e`        | `Some(self)`    | `None`             |\n| `AsResult`     | `Result\u003cSelf, E\u003e`     | `Ok(self)`      | `Err(error)`       |\n| `AsExpression` | `Expression\u003cSelf, E\u003e` | `Defined(self)` | `Undefined(error)` |\n\nIn the table above, `Self` refers to a `Constrained` type and `E` refers to the\nassociated error type of its constraint. Note that only the `OrPanic` divergence\nsupports `AsSelf` and can output the same type as its input type for fallible\noperations (just like primitive IEEE 754 floating-point types).\n\nWith the sole exception of `AsSelf`, the output type of fallible operations is\nextrinsic: fallible operations produce types that differ from their input types.\nThe `Expression` type, which somewhat resembles the standard `Result` type,\nimproves the ergonomics of error handling by implementing mathematical traits\nsuch that it can be used directly in expressions and defer error checking.\n\n```rust\nuse decorum::constraint::IsReal;\nuse decorum::divergence::{AsExpression, OrError};\nuse decorum::proxy::{Constrained, OutputFor};\nuse decorum::real::UnaryRealFunction;\nuse decorum::try_expression;\n\npub type Real = Constrained\u003cf64, IsReal\u003cOrError\u003cAsExpression\u003e\u003e\u003e;\npub type Expr = OutputFor\u003cReal\u003e;\n\npub fn f(x: Real, y: Real) -\u003e Expr {\n    let sum = x + y;\n    sum * g(x)\n}\n\npub fn g(x: Real) -\u003e Expr {\n    x + Real::ONE\n}\n\nlet x: Real = try_expression! { f(Real::E, -Real::ONE) };\n// ...\n```\n\nWhen using a nightly Rust toolchain with the `unstable` [Cargo\nfeature](#cargo-features) enabled, `Expression` also supports the (at time of\nwriting) unstable `Try` trait and try operator `?`.\n\n```rust\n// As above, but using the try operator `?`.\nlet x: Real = f(Real::E, -Real::ONE)?;\n```\n\n`Constrained` types support numerous constructions and conversions depending on\nconfiguration, including conversions for references, slices, subsets, supersets,\nand more. Conversions are provided via inherent functions and implementations of\nthe standard `From` and `TryFrom` traits. The following inherent functions are\nsupported by all `Constrained` types, though some more bespoke constructions are\navailable for specific configurations.\n\n| Method                 | Input     | Output    | Error         |\n|------------------------|-----------|-----------|---------------|\n| `new`                  | primitive | proxy     | break         |\n| `assert`               | primitive | proxy     | **panic**     |\n| `try_new`              | primitive | proxy     | `Result::Err` |\n| `try_from_{mut_}slice` | primitive | proxy     | `Result::Err` |\n| `into_inner`           | proxy     | primitive |               |\n| `from_subset`          | proxy     | proxy     |               |\n| `into_superset`        | proxy     | proxy     |               |\n\nThe following type definitions provide common proxy configurations. Each type\nimplements different traits that describe the supported encoding and elements of\nIEEE 754 floating-point based on its constraints.\n\n| Type Definition | Sized Aliases | Trait Implementations                           | Illegal Values        |\n|-----------------|---------------|-------------------------------------------------|-----------------------|\n| `Total`         |               | `BaseEncoding + InfinityEncoding + NanEncoding` |                       |\n| `ExtendedReal`  | `E32`, `E64`  | `BaseEncoding + InfinityEncoding`               | `NaN`                 |\n| `Real`          | `R32`, `R64`  | `BaseEncoding`                                  | `NaN`, `-INF`, `+INF` |\n\n## Relations and Total Ordering\n\nDecorum provides the following non-standard total ordering for IEEE 754\nfloating-point representations:\n\n```\n-INF \u003c ... \u003c 0 \u003c ... \u003c +INF \u003c NaN\n```\n\nIEEE 754 floating-point encoding has multiple representations of zero (`-0` and\n`+0`) and `NaN`. This ordering and equivalence relations consider all zero and\n`NaN` representations equal, which differs from the [standard partial\nordering](https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN).\n\nSome proxy types disallow unordered `NaN` values and therefore support a total\nordering based on the ordered subset of non-`NaN` floating-point values.\n`Constrained`\ntypes that use `IsFloat` (such as the `Total` type definition) support `NaN` but\nuse the total ordering described above to implement the standard `Eq`, `Hash`,\nand `Ord` traits.\n\nThe following traits can be used to compare and hash primitive floating-point\nvalues (including slices) using this non-standard relation.\n\n| Floating-Point Trait | Standard Trait   |\n|----------------------|------------------|\n| `CanonicalEq`        | `Eq`             |\n| `CanonicalHash`      | `Hash`           |\n| `CanonicalOrd`       | `Ord`            |\n\n```rust\nuse decorum::cmp::CanonicalEq;\n\nlet x = 0.0f64 / 0.0f64; // `NaN`.\nlet y = f64::INFINITY + f64::NEG_INFINITY; // `NaN`.\nassert!(x.eq_canonical(\u0026y));\n```\n\nDecorum also provides the `EmptyOrd` trait and the `min_or_empty` and\n`max_or_empty` functions. This trait defines a particular ordering for types\nthat may have a notion of empty inhabitants. An empty inhabitant is considered\nincomparable, and comparisons return an empty inhabitant when encountered. For\nexample, `None` is the empty inhabitant for `Option`. For floating-point types\n(including proxy types), `NaN`s are considered empty inhabitants. `EmptyOrd`\nfunctions forward `NaN`s when comparing these types just like most numeric\noperations (unlike `f64::max`, etc.).\n\n```rust\nuse decorum::cmp;\nuse decorum::real::{Endofunction, RealFunction, UnaryRealFunction};\n\npub fn f\u003cT\u003e(x: T, y: T) -\u003e T\nwhere\n    T: Endofunction + RealFunction,\n{\n    // `min` is assigned an empty inhabitant if either `x` or `y` are an empty\n    // inhabitant. For `T`, the empty inhabitants are `NaN`s, so this function\n    // forwards any input `NaN`s to its output.\n    let min = cmp::min_or_empty(x, y);\n    min * T::PI\n}\n```\n\n## Mathematical Traits\n\nThe `real` module provides various traits that describe real numbers and\nconstructions via IEEE 754 floating-point types. These traits model functions\nand operations on real numbers and specify a codomain for functions where the\noutput is not mathematically confined to the reals or a floating-point exception\nmay yield a non-real approximation or error. For example, the logarithm of zero\nis undefined and the sum of two very large reals results in an infinity in IEEE\n754. For proxy types, the codomain is the same as the branch type of its\ndivergence (see above).\n\nReal number and IEEE 754 encoding traits can both be used for generic\nprogramming. The following code demonstrates a function that accepts types that\nsupport floating-point infinities and real functions.\n\n```rust\nuse decorum::real::{Endofunction, RealFunction};\nuse decorum::InfinityEncoding;\n\nfn f\u003cT\u003e(x: T, y: T) -\u003e T\nwhere\n    T: Endofunction + InfinityEncoding + RealFunction,\n{\n    let z = x / y;\n    if z.is_infinite() {\n        x + y\n    }\n    else {\n        z + y\n    }\n}\n```\n\n## Cargo Features\n\nDecorum supports the following feature flags.\n\n| Feature    | Default | Description                                                  |\n|------------|---------|--------------------------------------------------------------|\n| `approx`   | yes     | Implements traits from [`approx`] for `Constrained` types.   |\n| `serde`    | yes     | Implements traits from [`serde`] for `Constrained` types.    |\n| `std`      | yes     | Integrates the `std` library and enables dependent features. |\n| `unstable` | no      | Enables features that require an unstable compiler.          |\n\n[`approx`]: https://crates.io/crates/approx\n[`num-traits`]: https://crates.io/crates/num-traits\n[`serde`]: https://crates.io/crates/serde\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folson-sean-k%2Fdecorum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Folson-sean-k%2Fdecorum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folson-sean-k%2Fdecorum/lists"}