{"id":29116487,"url":"https://github.com/quagmt/udecimal","last_synced_at":"2026-01-14T21:07:05.431Z","repository":{"id":257825702,"uuid":"828495384","full_name":"quagmt/udecimal","owner":"quagmt","description":"A high-performance, high precision, zero allocation fixed-point decimal library for financial applications","archived":false,"fork":false,"pushed_at":"2025-06-19T14:47:52.000Z","size":456,"stargazers_count":149,"open_issues_count":1,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-29T11:13:57.466Z","etag":null,"topics":["decimal","decimals","financial","go","golang","high-performance","money","zero-allocation"],"latest_commit_sha":null,"homepage":"https://quagmt.github.io/udecimal/","language":"Go","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/quagmt.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":"2024-07-14T10:27:19.000Z","updated_at":"2025-06-25T03:18:19.000Z","dependencies_parsed_at":"2024-11-08T15:21:40.465Z","dependency_job_id":"099dbb21-8cd7-45a7-a47b-d815cd68b663","html_url":"https://github.com/quagmt/udecimal","commit_stats":null,"previous_names":["quagmt/udecimal"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/quagmt/udecimal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quagmt%2Fudecimal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quagmt%2Fudecimal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quagmt%2Fudecimal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quagmt%2Fudecimal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quagmt","download_url":"https://codeload.github.com/quagmt/udecimal/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quagmt%2Fudecimal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28434546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T18:57:19.464Z","status":"ssl_error","status_checked_at":"2026-01-14T18:52:48.501Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["decimal","decimals","financial","go","golang","high-performance","money","zero-allocation"],"created_at":"2025-06-29T11:13:38.990Z","updated_at":"2026-01-14T21:07:05.405Z","avatar_url":"https://github.com/quagmt.png","language":"Go","readme":"# udecimal\n\n[![build](https://github.com/quagmt/udecimal/actions/workflows/test.yaml/badge.svg)](https://github.com/quagmt/udecimal/actions/workflows/test.yaml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/quagmt/udecimal)](https://goreportcard.com/report/github.com/quagmt/udecimal)\n[![codecov](https://codecov.io/gh/quagmt/udecimal/graph/badge.svg?token=662ET843EZ)](https://codecov.io/gh/quagmt/udecimal)\n[![GoDoc](https://pkg.go.dev/badge/github.com/quagmt/udecimal)](https://pkg.go.dev/github.com/quagmt/udecimal)\n[![Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#financial)\n\nHigh performance, high precision, zero allocation fixed-point decimal number for financial applications.\n\n## Installation\n\nSupported version: Go \u003e= 1.23\n\n```sh\ngo get github.com/quagmt/udecimal\n```\n\n## Features\n\n- **High Precision**: Supports up to 19 decimal places with no precision loss during arithmetic operations.\n- **Zero Memory Allocation**: Designed for almost 99% zero memory allocation (see [How it works](#how-it-works)).\n- **Optimized for Speed**: 5x~20x faster than [shopspring/decimal](https://github.com/shopspring/decimal) and [ericlagergren/decimal](https://github.com/ericlagergren/decimal) (see [Benchmark](benchmarks/README.md)).\n- **Panic-Free**: All errors are returned as values, ensuring no unexpected panics.\n- **Concurrent-Safe**: All arithmetic operations return a new `Decimal` value while keeping the original value unchanged, making it safe to be shared across goroutines.\n- **Correctness**: All arithmetic operations are fuzz tested and cross-checked with `shopspring/decimal` library to ensure correctness.\n- **Versatile Rounding Methods**: Includes HALF AWAY FROM ZERO, HALF TOWARD ZERO, AWAY FROM ZERO, and Banker's rounding.\n  \u003cbr/\u003e\n\n**NOTE**: This library does not perform implicit rounding. If the result of an operation exceeds the maximum precision, extra digits are truncated. All rounding methods must be explicitly invoked. (see [Rounding Methods](#rounding-methods) for more details)\n\n## Documentation\n\n- Checkout [documentation](https://pkg.go.dev/github.com/quagmt/udecimal) for more information.\n\n## Usage\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/quagmt/udecimal\"\n)\n\nfunc main() {\n\t// Create a new decimal number\n\ta, _ := udecimal.NewFromInt64(123456, 3)              // a = 123.456\n\tb, _ := udecimal.NewFromInt64(-123456, 4)             // b = -12.3456\n\tc, _ := udecimal.NewFromFloat64(1.2345)               // c = 1.2345\n\td, _ := udecimal.Parse(\"4123547.1234567890123456789\") // d = 4123547.1234567890123456789\n\n\t// Basic arithmetic operations\n\tfmt.Println(a.Add(b)) // 123.456 - 12.3456 = 111.1104\n\tfmt.Println(a.Sub(b)) // 123.456 + 12.3456 = 135.8016\n\tfmt.Println(a.Mul(b)) // 123.456 * -12.3456 = -1524.1383936\n\tfmt.Println(a.Div(b)) // 123.456 / -12.3456 = -10\n\tfmt.Println(a.Div(d)) // 123.456 / 4123547.1234567890123456789 = 0.0000299392722585176\n\n\t// Rounding\n\tfmt.Println(c.RoundBank(3))         // banker's rounding: 1.2345 -\u003e 1.234\n\tfmt.Println(c.RoundAwayFromZero(2)) // round away from zero: 1.2345 -\u003e 1.24\n\tfmt.Println(c.RoundHAZ(3))          // half away from zero: 1.2345 -\u003e 1.235\n\tfmt.Println(c.RoundHTZ(3))          // half towards zero: 1.2345 -\u003e 1.234\n\tfmt.Println(c.Trunc(2))             // truncate: 1.2345 -\u003e 1.23\n\tfmt.Println(c.Floor())              // floor: 1.2345 -\u003e 1\n\tfmt.Println(c.Ceil())               // ceil: 1.2345 -\u003e 2\n\n\t// Display\n\tfmt.Println(a.String())         // 123.456\n\tfmt.Println(a.StringFixed(10))  // 123.4560000000\n\tfmt.Println(a.InexactFloat64()) // 123.456\n}\n```\n\n## Why another decimal library?\n\nThere are already a couple of decimal libraries available in Go, such as [shopspring/decimal](https://github.com/shopspring/decimal), [cockroachdb/apd](https://github.com/cockroachdb/apd), [govalues/decimal](https://github.com/govalues/decimal), etc. However, each of these libraries has its own limitations, for example:\n\n- [shopspring/decimal](https://github.com/shopspring/decimal) is great for general-purpose decimal arithmetic because of arbitrary precision. However, it's slow and requires memory allocation for every arithmetic operation. Also in financial applications, arbitrary precision is not always necessary.\n- [cockroachdb/apd](https://github.com/cockroachdb/apd) is faster but still requires memory allocation. Also the API is not very intuitive.\n- [govalues/decimal](https://github.com/govalues/decimal) is fast, no memory allocation, easy to use but the data range is only limited to 19 digits (include both the integer and fractional parts). Some operations (especially Quo/QuoRem) usually overflow and fallback to use big.Int API, which hurts the performance. Another limitation is that it starts losing precision when the total number of digits exceeds 19.\n\nThis library is designed to address these limitations, providing both high performance and zero allocation while maintaining an acceptable range of precision, which is suitable for most financial applications.\n\n## Rounding Methods\n\nRounding numbers can often be challenging and confusing due to the [variety of methods](https://www.mathsisfun.com/numbers/rounding-methods.html) available. Each method serves specific purposes, and it's common for developers to make mistakes or incorrect assumptions about how rounding should be performed. For example, the result of `round(1.45)` could be either 1.4 or 1.5, depending on the rounding method used.\n\nThis issue is particularly critical in financial applications, where even minor rounding errors can accumulate and lead to significant financial losses. To mitigate such errors, this library intentionally avoids implicit rounding. If the result of an operation exceeds the maximum precision specified by developers beforehand, **extra digits are truncated**. Developers need to explicitly choose the rounding method they want to use. The supported rounding methods are:\n\n- [Banker's rounding](https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even) or round half to even\n- [Round away from zero](https://en.wikipedia.org/wiki/Rounding#Rounding_away_from_zero)\n- [Half away from zero](https://en.wikipedia.org/wiki/Rounding#Rounding_half_away_from_zero) (HAZ)\n- [Half toward zero](https://en.wikipedia.org/wiki/Rounding#Rounding_half_toward_zero) (HTZ)\n\n### Examples:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/quagmt/udecimal\"\n)\n\nfunc main() {\n\t// Create a new decimal number\n\ta, _ := udecimal.NewFromFloat64(1.345) // a = 1.345\n\n\t// Rounding\n\tfmt.Println(a.RoundBank(2))         // banker's rounding: 1.345 -\u003e 1.34\n\tfmt.Println(a.RoundAwayFromZero(2)) // round away from zero: 1.345 -\u003e 1.35\n\tfmt.Println(a.RoundHAZ(2))          // half away from zero: 1.345 -\u003e 1.35\n\tfmt.Println(a.RoundHTZ(2))          // half towards zero: 1.345 -\u003e 1.34\n}\n```\n\n## How it works\n\nAs mentioned above, this library is not always memory allocation free. However, those cases where we need to allocate memory are incredibly rare. To understand why, let's take a look at how the `Decimal` type is implemented.\n\nThe `Decimal` type represents a fixed-point decimal number. It consists of three components: sign, coefficient, and prec. The number is represented as:\n\n```go\n// decimal value = (neg == true ? -1 : 1) * coef * 10^(-prec)\ntype Decimal struct {\n\tcoef bint\n\tneg bool\n\tprec uint8 // 0 \u003c= prec \u003c= 19\n}\n\n// Example:\n// 123.456 = 123456 * 10^-3\n// -\u003e neg = false, coef = 123456, prec = 3\n\n// -123.456 = -123456 / 10^-3\n// -\u003e neg = true, coef = 123456, prec = 3\n```\n\nYou can notice that `coef` data type is `bint`, which is a custom data type:\n\n```go\ntype bint struct {\n\t// For coefficients exceeding u128\n\tbigInt *big.Int\n\n\t// For coefficients less than 2^128\n\tu128 u128\n}\n```\n\nThe `bint` type can store coefficients up to `2^128 - 1` using `u128`. Arithmetic operations with `u128` are fast and require no memory allocation. If result of an arithmetic operation exceeds u128 capacity, the whole operation will be performed using `big.Int` API. Such operations are slower and do involve memory allocation. However, those cases are rare in financial applications due to the extensive range provided by a 128-bit unsigned integer, for example:\n\n- If precision is 0, the decimal range it can store is:\n  `[-340282366920938463463374607431768211455, 340282366920938463463374607431768211455]`(approximately -340 to 340 undecillion)\n\n- If precision is 19, the decimal range becomes:\n  `[-34028236692093846346.3374607431768211455, 34028236692093846346.3374607431768211455]` (approximately -34 to 34 quintillion)\n\nTherefore, in most cases you can expect high performance and no memory allocation when using this library.\n\n## Credits\n\nThis library is inspired by these repositories:\n\n- [govalues/decimal](https://github.com/govalues/decimal)\n- [lukechampine/uint128](https://github.com/lukechampine/uint128)\n- [ridiculousfish/libdivide](https://github.com/ridiculousfish/libdivide)\n","funding_links":[],"categories":["Financial","金融"],"sub_categories":["Search and Analytic Databases","检索及分析资料库"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquagmt%2Fudecimal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquagmt%2Fudecimal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquagmt%2Fudecimal/lists"}