{"id":21257890,"url":"https://github.com/cathei/incremental","last_synced_at":"2025-07-11T02:32:17.903Z","repository":{"id":60671413,"uuid":"542076456","full_name":"cathei/Incremental","owner":"cathei","description":"Incremental Deterministic Decimal Number Type in C#","archived":false,"fork":false,"pushed_at":"2022-12-31T20:37:54.000Z","size":149,"stargazers_count":5,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2023-06-02T07:21:59.431Z","etag":null,"topics":["biginteger","csharp","decimal","deterministic","idle-game","incremental-game","number"],"latest_commit_sha":null,"homepage":"","language":"C#","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/cathei.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}},"created_at":"2022-09-27T12:35:56.000Z","updated_at":"2023-04-27T03:28:15.000Z","dependencies_parsed_at":"2023-01-31T19:45:15.497Z","dependency_job_id":null,"html_url":"https://github.com/cathei/Incremental","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cathei%2FIncremental","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cathei%2FIncremental/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cathei%2FIncremental/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cathei%2FIncremental/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cathei","download_url":"https://codeload.github.com/cathei/Incremental/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225669507,"owners_count":17505386,"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":["biginteger","csharp","decimal","deterministic","idle-game","incremental-game","number"],"created_at":"2024-11-21T04:06:18.276Z","updated_at":"2024-11-21T04:06:18.887Z","avatar_url":"https://github.com/cathei.png","language":"C#","readme":"# Incremental 📈\nIncremental Deterministic Decimal Number type in C#\n\n## Features\n* 128-bit number type\n  * 1-bit sign\n  * 57-bit mantissa\n  * 64-bit exponent\n* Decimal representation (No binary rounding error)\n* Deterministic math calculation\n* Reasonable precision (17 decimal digits)\n* HUGE representation range from 1E-(2^63) to 9.99E+(2^63-1)\n  * Means you can have 9,223,372,036,854,775,807 zeros\n\n## Installation\nClone this repository and copy cs files under `Incremental` folder to your project.\n\n## Comparison\n| Category         | Incremental          | C# decimal       | BreakInfinity BigDouble   |\n|------------------|----------------------|---------------|---------------------------|\n| Size             | 16 bytes (long+long) | 16 bytes      | 16 bytes (double+long)    |\n| Representation   | decimal (base 10)             | decimal (base 10)       | binary (base 2)                   |\n| Deterministic?   | Yes                  | Yes           | No                        |\n| Precision        | 17 digits            | 28~29 digits     | 15~17 digits                 |\n| Exponent (Up to) | 64 bits (E+2^63-1)   | 8 bits (E+28) | 64+11 bits (E+2^63-1+308) |\n\nSince `Incremental` uses decimal representation, you are able to write exact number as `0.1`,\nwhich is actually `0.1000000000000000055511151231257827021181583404541015625` when you write in `double` type.\nDue to this behaviour, `Incremental` does not suffer from binary rounding errors.\nIt would be a better choice when you want to use same type for incremental currencies and regular ones.\n\n`Incremental` also support deterministic calculation across platforms.\nFor example, you could use it for input-synced lockstep scenario with incremental stats.\n\nOverall, you should consider using `Incremental` when you want very big number with decimal places and/or deterministic behaviour.\n\n## Benchmarks\nYou can see the benchmark results in [Incremental.Benchmarks](Incremental.Benchmarks).\n\n## Implementation Details\n### Data\n`Incremental` type has two `long` variable, `Mantissa` and `Exponent`.\n\n`Mantissa` is normalized decimal representation of fixed point number\nwhere `10,000,000,000,000,000` (or `Unit`) is `1` and `99,990,000,000,000,000` is `9.999`.\n`Mantissa` is signed and can represent negative number.\nAbsolute value of `Mantissa` is always `Unit \u003c= x \u003c Unit * 10`, except when it is `0`.\n\n`Exponent` is power of 10 value to multiply `Mantissa`. `Exponent` is signed and can represent smaller value than `1`.\n\n### Multiplication\n128-bit math is not native in 64-bit system, `Incremental` does partial multiplication.\n\nFor multiplication, the result mantissa would be `a * b / Unit`.\nSince result of `a * b` will overflow in 64-bit size, `Incremental` has to calculate `a / Unit` first then multiply by `b`.\n\nWe can represent a fractal part of `1 / Unit` (`0x0.000...734ACA5F6226F0ADA6...`), then by shifting it left to remove leading zeros for precision.\nThen we get magic number `0xE69594BEC44DE15B` which is `(1 / Unit) \u003c\u003c 53 \u003c\u003c 64`.\n\nWe can remove unused bit of `a`'s mantissa with shifting it's value left by 7 bits, then multiply with magic number.\nThe full result will be 128-bit, but we are only need to calculate upper 64-bit since the result is already shifted.\nTaking upper half would be same as shift total result to right by 64, so the result is `(a / Unit) \u003c\u003c 60`.\n\nAs same as earlier, we can shift `b` by 7 bits, multiply with the previous result then take the upper 64-bit.\nThe result is `(a / Unit * b) \u003c\u003c 3`, so by shifting 3 bits to right we can get the final result.\n\nThe procedural is fast because only multiplication is involved. It is similar to what compiler does to optimize division.\nFurther reading: [Explanation on StackOverflow](https://stackoverflow.com/questions/28868367/getting-the-high-part-of-64-bit-integer-multiplication)\n\n### Division\nAs same reason as multiplication, we have to do partial division.\nHowever partial division is not simple as multiplication, we cannot simply choose to take upper bit and divide.\n\nWhile other algorithm is required for full division of 128-bit dividend and 64-bit divisor,\nUsing some unused bits of `Incremental` data type, we can calculate the quotient with multiple 64-bit division.\n\nBy removing leading zero of dividend and trailing zeros of divisor, we can do partial division and get intermediate quotient.\nShift and add the quotient to result. If there is remainder, we can repeat the procedure until there is no remainder or bits are not significant anymore.\n\nFinally, doing multiplication between binary quotient and `Unit`, we can get normalized mantissa of the quotient.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcathei%2Fincremental","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcathei%2Fincremental","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcathei%2Fincremental/lists"}