{"id":35272204,"url":"https://github.com/mamrhein/rust-fixed-point-decimal","last_synced_at":"2026-04-09T04:03:17.424Z","repository":{"id":57665233,"uuid":"390043311","full_name":"mamrhein/rust-fixed-point-decimal","owner":"mamrhein","description":"Decimal fixed-point arithmetic.","archived":false,"fork":false,"pushed_at":"2021-11-26T16:46:31.000Z","size":281,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-03T00:25:48.019Z","etag":null,"topics":["arithmetic","decimal","fixed-point","number","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mamrhein.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.TXT","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-07-27T15:57:06.000Z","updated_at":"2023-11-23T22:26:27.000Z","dependencies_parsed_at":"2022-09-26T21:31:33.619Z","dependency_job_id":null,"html_url":"https://github.com/mamrhein/rust-fixed-point-decimal","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mamrhein/rust-fixed-point-decimal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mamrhein%2Frust-fixed-point-decimal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mamrhein%2Frust-fixed-point-decimal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mamrhein%2Frust-fixed-point-decimal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mamrhein%2Frust-fixed-point-decimal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mamrhein","download_url":"https://codeload.github.com/mamrhein/rust-fixed-point-decimal/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mamrhein%2Frust-fixed-point-decimal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31584820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"online","status_checked_at":"2026-04-09T02:00:06.848Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["arithmetic","decimal","fixed-point","number","rust"],"created_at":"2025-12-30T12:34:23.335Z","updated_at":"2026-04-09T04:03:17.406Z","avatar_url":"https://github.com/mamrhein.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Note\n\n**The developpment of this package has been ceased, in favor of\n[fpdec.rs](\"https://github.com/mamrhein/fpdec.rs\").**\n\nBeing based on const generics, this implementation of a fixed-point Decimal\ntype provides some advantages:\n\n* Compact memory representation (16 bytes),\n* Very good performance.\n\nHaving the number of fractional digits as a constant type parameter provides\nthe compiler with some extra opportunities to optimize the generated code. \nFor example, in the implementation of the Add trait:\n\n```\nimpl\u003cconst P: u8, const Q: u8\u003e Add\u003cDecimal\u003cQ\u003e\u003e for Decimal\u003cP\u003e\nwhere\n    PrecLimitCheck\u003c{ P \u003c= MAX_PREC }\u003e: True,\n    PrecLimitCheck\u003c{ Q \u003c= MAX_PREC }\u003e: True,\n    PrecLimitCheck\u003c{ const_max_u8(P, Q) \u003c= MAX_PREC }\u003e: True,\n{\n    type Output = Decimal\u003c{ const_max_u8(P, Q) }\u003e;\n\n    fn add(self, other: Decimal\u003cQ\u003e) -\u003e Self::Output {\n        match P.cmp(\u0026Q) {\n            Ordering::Equal =\u003e Self::Output {\n                coeff: Add::add(self.coeff, other.coeff),\n            },\n            Ordering::Greater =\u003e Self::Output {\n                coeff: Add::add(\n                    self.coeff,\n                    mul_pow_ten(other.coeff, P - Q),\n                ),\n            },\n            Ordering::Less =\u003e Self::Output {\n                coeff: Add::add(\n                    mul_pow_ten(self.coeff, Q - P),\n                    other.coeff,\n                ),\n            },\n        }\n    }\n}\n```\n\nFor each combination of P and Q the compiler can reduce the code for the \nmatch statement to just one case.\n\nAnd the multiplication of two Decimals is reduced to the multiplication of two \nintegers (i128), because the resulting number of fractional digits is already\ndetermined at compile time:\n\n```\nimpl\u003cconst P: u8, const Q: u8\u003e Mul\u003cDecimal\u003cQ\u003e\u003e for Decimal\u003cP\u003e\nwhere\n    PrecLimitCheck\u003c{ P \u003c= MAX_PREC }\u003e: True,\n    PrecLimitCheck\u003c{ Q \u003c= MAX_PREC }\u003e: True,\n    PrecLimitCheck\u003c{ (const_sum_u8(P, Q)) \u003c= MAX_PREC }\u003e: True,\n{\n    type Output = Decimal\u003c{ const_sum_u8(P, Q) }\u003e;\n\n    #[inline(always)]\n    fn mul(self, other: Decimal\u003cQ\u003e) -\u003e Self::Output {\n        Self::Output {\n            coeff: self.coeff * other.coeff,\n        }\n    }\n}\n```\n\nBut there are also some serious drawbacks:\n\n* The large number of variants of the generic functions results in large \n  binary code files.\n* Because each Decimal\\\u003cP\\\u003e is a different type, there some unusual \n  asymmetries. For example, multipliying two Decimal\\\u003cP\\\u003e does not result in a \n  Decimal\\\u003cP\\\u003e. I.e. Decimal\\\u003cP\\\u003e does not satisfy Mul\\\u003cSelf, Output = Self\\\u003e \n  like other numerical types.\n* Depends on nightly features.\n\nOverall, the performance gains stemming from the use of const generics do not\noutweigh the disadvantages.\n\nThe package [fpdec.rs](\"https://github.com/mamrhein/fpdec.rs\") follows the\nsame objectives as this package. It does not provide the same performance,\nbut avoids the drawbacks mentioned above.\n\n# ----------\n\nThis crate strives to provide a fast implementation of `Decimal` fixed-point \narithmetics.\n\nIt is targeted at typical business applications, dealing with numbers \nrepresenting quantities, money and the like, not at scientific computations,\nfor which the accuracy of floating point math is - in most cases - sufficient.\n\n### Objectives\n\n* \"Exact\" representation of decimal numbers (no deviation as with binary\n  floating point numbers)\n* No hidden rounding errors (as inherent to floating point math)\n* Very fast operations (by mapping them to integer ops) \n* Range of representable decimal numbers sufficient for typical business\n  applications\n\nAt the binary level a Decimal number is represented as a coefficient (stored \nas an `i128` value) combined with a type parameter specifying the number of \nfractional decimal digits. I. e., the whole implementation is based on \"const \ngenerics\" and needs a rust version supporting this feature.\n\n### Status\n\nExperimental (work in progess)\n\n## Getting started\n\nAdd `rust-fixed-point-decimal` to your `Cargo.toml`:\n\n```toml\n[dependencies]\nrust-fixed-point-decimal = \"0.1\"\n```\n\n### Note:\n\nBecause the implementation of \"const generics\" is still incomplete, you have \nto put the following at the start of your main.rs or lib.rs file:\n\n```rust\n#![allow(incomplete_features)]\n#![feature(generic_const_exprs)]\n```\n\n## Usage\n\nA `Decimal` number can be created in different ways. \n\nThe easiest method is to use the procedural macro `Dec`:\n\n```rust\n# use rust_fixed_point_decimal::Dec;\nlet d = Dec!(-17.5);\nassert_eq!(d.to_string(), \"-17.5\");\n```\n\nAlternatively you can convert an integer, a float or a string to a `Decimal`:\n\n```rust\n# use rust_fixed_point_decimal::Decimal;\nlet d = Decimal::\u003c2\u003e::from(297_i32);\nassert_eq!(d.to_string(), \"297.00\");\n```\n\n```rust\n# #![allow(incomplete_features)]\n# #![feature(generic_const_exprs)]\n# use rust_fixed_point_decimal::{Decimal, DecimalError};\n# use std::convert::TryFrom;\nlet d = Decimal::\u003c5\u003e::try_from(83.0025)?;\nassert_eq!(d.to_string(), \"83.00250\");\n# Ok::\u003c(), DecimalError\u003e(())\n```\n\n```rust\n# #![allow(incomplete_features)]\n# #![feature(generic_const_exprs)]\n# use rust_fixed_point_decimal::{Decimal, ParseDecimalError};\n# use std::str::FromStr;\nlet d = Decimal::\u003c4\u003e::from_str(\"38.207\")?;\nassert_eq!(d.to_string(), \"38.2070\");\n# Ok::\u003c(), ParseDecimalError\u003e(())\n```\n\nThe sign of a `Decimal` can be inverted using the unary minus operator and a\n`Decimal` instance can be compared to other instances of type `Decimal` or all\nbasic types of integers (besides u128 and atm besides u8, which causes a \ncompiler error):\n\n```rust\n# #![allow(incomplete_features)]\n# #![feature(generic_const_exprs)]\n# use rust_fixed_point_decimal::{Dec, Decimal};\nlet x = Dec!(129.24);\nlet y = -x;\nassert_eq!(y.to_string(), \"-129.24\");\nassert!(-129_i64 \u003e y);\nlet z = -y;\nassert_eq!(x, z);\nlet z = Dec!(0.00097);\nassert!(x \u003e z);\nassert!(y \u003c= z);\nassert!(z != 7_u32);\nassert!(7_u32 == Dec!(7.00));\n```\n\n`Decimal` supports all five binary numerical operators +, -, *, /, and %, with\ntwo `Decimal`s or with a `Decimal` and a basic integer (besides u128):\n\n```rust\n# #![allow(incomplete_features)]\n# #![feature(generic_const_exprs)]\n# use rust_fixed_point_decimal::{Dec, Decimal};\nlet x = Dec!(17.5);\nlet y = Dec!(6.40);\nlet z = x + y;\nassert_eq!(z.to_string(), \"23.90\");\nlet z = x - y;\nassert_eq!(z.to_string(), \"11.10\");\nlet z = x * y;\nassert_eq!(z.to_string(), \"112.000\");\nlet z = x / y;\nassert_eq!(z.to_string(), \"2.734375000\");\nlet z = x % y;\nassert_eq!(z.to_string(), \"4.70\");\n```\n\n```rust\n# #![allow(incomplete_features)]\n# #![feature(generic_const_exprs)]\n# use rust_fixed_point_decimal::{Dec, Decimal};\nlet x = Dec!(17.5);\nlet y = -5_i64;\nlet z = x + y;\nassert_eq!(z.to_string(), \"12.5\");\nlet z = x - y;\nassert_eq!(z.to_string(), \"22.5\");\nlet z = y * x;\nassert_eq!(z.to_string(), \"-87.5\");\nlet z = x / y;\nassert_eq!(z.to_string(), \"-3.500000000\");\nlet z = x % y;\nassert_eq!(z.to_string(), \"2.5\");\n```\n\nAll these binary numeric operators panic if the result is not representable as \na `Decimal` according to the constraints stated above. In addition there are\nfunctions implementing \"checked\" variants of the operators which return \n`Option::None` instead of panicking.\n\nFor Multiplication and Division there are also functions which return a result\nrounded to a number of fractional digits determined by the target type:\n\n```rust\n# #![allow(incomplete_features)]\n# #![feature(generic_const_exprs)]\n# use rust_fixed_point_decimal::{Dec, Decimal, DivRounded, MulRounded};\nlet x = Dec!(17.5);\nlet y = Dec!(6.47);\nlet z: Decimal\u003c1\u003e = x.mul_rounded(y);\nassert_eq!(z.to_string(), \"113.2\");\nlet z: Decimal\u003c3\u003e = x.div_rounded(y);\nassert_eq!(z.to_string(), \"2.705\");\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmamrhein%2Frust-fixed-point-decimal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmamrhein%2Frust-fixed-point-decimal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmamrhein%2Frust-fixed-point-decimal/lists"}