{"id":18843289,"url":"https://github.com/alpacahq/alpacadecimal","last_synced_at":"2025-08-04T04:34:01.740Z","repository":{"id":65349818,"uuid":"540517778","full_name":"alpacahq/alpacadecimal","owner":"alpacahq","description":"Arbitrary-precision fixed-point decimal numbers in go. Similar and compatible with shopspring's decimal.Decimal, but optimized for Alpaca's data sets.","archived":false,"fork":false,"pushed_at":"2025-04-07T19:32:16.000Z","size":294,"stargazers_count":43,"open_issues_count":5,"forks_count":6,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-04-07T20:23:36.419Z","etag":null,"topics":["currency","decimals","go","golang","math","money","precision","trading"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/alpacahq/alpacadecimal","language":"Go","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/alpacahq.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":"2022-09-23T16:02:59.000Z","updated_at":"2025-04-02T05:03:54.000Z","dependencies_parsed_at":"2025-01-21T22:27:13.842Z","dependency_job_id":"f379fd8b-cf54-4ae0-aae4-02a12e7b113b","html_url":"https://github.com/alpacahq/alpacadecimal","commit_stats":{"total_commits":18,"total_committers":2,"mean_commits":9.0,"dds":"0.16666666666666663","last_synced_commit":"c1fe20ea15ea45e0f47ec7d65e6c47aab14fad07"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpacahq%2Falpacadecimal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpacahq%2Falpacadecimal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpacahq%2Falpacadecimal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpacahq%2Falpacadecimal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alpacahq","download_url":"https://codeload.github.com/alpacahq/alpacadecimal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248839507,"owners_count":21169823,"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":["currency","decimals","go","golang","math","money","precision","trading"],"created_at":"2024-11-08T02:57:25.252Z","updated_at":"2025-04-14T07:32:18.350Z","avatar_url":"https://github.com/alpacahq.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# alpacadecimal\nSimilar and compatible with [decimal.Decimal](https://pkg.go.dev/github.com/shopspring/decimal), but optimized for Alpaca's data sets.\n\n### Goal\n- optimize for Alpaca data sets (99% of decimals are within 10 millions with up to 12 precisions).\n- compatible with [decimal.Decimal](https://pkg.go.dev/github.com/shopspring/decimal) so that it could be a drop-in replacement for current `decimal.Decimal` usage.\n\n### Key Ideas\n\nThe original `decimal.Decimal` package has bottleneck on `big.Int` operations, e.g. sql serialization / deserialization, addition, multiplication etc. These operations took fair amount cpu and memory during\nour profiling / monitoring.\n\n![profiling result](doc/value-slowness.png)\n\nThe optimization this library is to represent most decimal numbers with `int64` instead of `big.Int`. To \nkeep this library to be compatible with original `decimal.Decimal` package, we use original as a fallback\nsolution when `int64` is not enough (e.g. number is too big / small, too many precisions).\n\nThe core data struct is like following:\n\n```golang\ntype Decimal struct {\n\t// represent decimal with 12 precision, 1.23 will have `fixed = 1_230_000_000_000`\n\t// max support decimal is 9_223_372.000_000_000_000\n\t// min support decimal is -9_223_372.000_000_000_000\n\tfixed int64\n\n\t// fallback to original decimal.Decimal if necessary\n\tfallback *decimal.Decimal\n}\n```\n\nWe pick 12 precisions because it could cover 99% of Alpaca common cases.\n\n\n### Compatibility\n\nIn general, `alpacadecimal.Decimal` is fully compatible with `decimal.Decimal` package, as `decimal.Decimal` is used as \na fallback solution for overflow cases.\n\nThere are a few special cases / APIs that `alpacadecimal.Decimal` behaves different from `decimal.Decimal` (behaviour is still\ncorrect / valid, just different). Affected APIs:\n\n- `Decimal.Exponent()`\n- `Decimal.Coefficient()`\n- `Decimal.CoefficientInt64()` \n- `Decimal.NumDigits()`\n\nFor optimized case, `alpacadecimal.Decimal` always assume that exponent is 12, which results in a valid but different decimal representation. For example,\n\n```golang\nx := alpacadecimal.NewFromInt(123)\nrequire.Equal(t, int32(-12), x.Exponent())\nrequire.Equal(t, \"123000000000000\", x.Coefficient().String())\nrequire.Equal(t, int64(123000000000000), x.CoefficientInt64())\nrequire.Equal(t, 15, x.NumDigits())\n\ny := decimal.NewFromInt(123)\nrequire.Equal(t, int32(0), y.Exponent())\nrequire.Equal(t, \"123\", y.Coefficient().String())\nrequire.Equal(t, int64(123), y.CoefficientInt64())\nrequire.Equal(t, 3, y.NumDigits())\n```\n\n### Related Issues\n- `big.NewInt` optimization from [here](https://go-review.googlesource.com/c/go/+/411254) might help to speed up some `big.Int` related operations.\n- `big.Int.String` slowness is tracked by [this issue](https://github.com/golang/go/issues/20906). The approach we reduce this slowness is to use int64 to represent the number if possible to avoid `big.Int` operations.\n\n### Benchmark\n\nGenerally, for general case (99%), the speedup varies from 5x to 100x.\n\n```\n$ make bench\ngo test -bench=. --cpuprofile profile.out --memprofile memprofile.out\ngoos: darwin\ngoarch: arm64\npkg: github.com/alpacahq/alpacadecimal\ncpu: Apple M3\nBenchmarkValue/alpacadecimal.Decimal_Cached_Case-8              579633375                2.084 ns/op\nBenchmarkValue/alpacadecimal.Decimal_Optimized_Case-8           33500136                35.10 ns/op\nBenchmarkValue/alpacadecimal.Decimal_Fallback_Case-8            12971452                91.12 ns/op\nBenchmarkValue/decimal.Decimal-8                                14983346                80.26 ns/op\nBenchmarkValue/eric.Decimal-8                                   13220779                93.22 ns/op\nBenchmarkAdd/alpacadecimal.Decimal-8                            863144540                1.385 ns/op\nBenchmarkAdd/decimal.Decimal-8                                  34509368                35.58 ns/op\nBenchmarkAdd/eric.Decimal-8                                     69539348                17.16 ns/op\nBenchmarkSub/alpacadecimal.Decimal-8                            501099547                2.394 ns/op\nBenchmarkSub/decimal.Decimal-8                                  40411579                28.76 ns/op\nBenchmarkSub/eric.Decimal-8                                     69800077                17.12 ns/op\nBenchmarkScan/alpacadecimal.Decimal-8                           122420659               10.02 ns/op\nBenchmarkScan/decimal.Decimal-8                                 12091557                99.72 ns/op\nBenchmarkScan/eric.Decimal-8                                    12087218                96.06 ns/op\nBenchmarkMul/alpacadecimal.Decimal-8                            323009985                3.722 ns/op\nBenchmarkMul/decimal.Decimal-8                                  33682357                34.52 ns/op\nBenchmarkMul/eric.Decimal-8                                     91006764                12.58 ns/op\nBenchmarkDiv/alpacadecimal.Decimal-8                            266056830                4.517 ns/op\nBenchmarkDiv/decimal.Decimal-8                                   8536772               139.9 ns/op\nBenchmarkDiv/eric.Decimal-8                                     83571278                14.34 ns/op\nBenchmarkString/alpacadecimal.Decimal-8                         613455636                1.958 ns/op\nBenchmarkString/decimal.Decimal-8                               15399207                77.92 ns/op\nBenchmarkString/eric.Decimal-8                                  14207025                82.22 ns/op\nBenchmarkRound/alpacadecimal.Decimal-8                          800181822                1.498 ns/op\nBenchmarkRound/decimal.Decimal-8                                10937922               109.2 ns/op\nBenchmarkRound/eric.Decimal-8                                   140659539                8.512 ns/op\nBenchmarkNewFromDecimal/alpacadecimal.Decimal.NewFromDecimal-8          100000000               11.68 ns/op\nBenchmarkNewFromDecimal/alpacadecimal.Decimal.RequireFromString-8       11680768               103.5 ns/op\nBenchmarkNewFromDecimal/alpacadecimal.Decimal.New-8                     645217516                1.865 ns/op\nPASS\nok      github.com/alpacahq/alpacadecimal       40.632s\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falpacahq%2Falpacadecimal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falpacahq%2Falpacadecimal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falpacahq%2Falpacadecimal/lists"}