Giter Site home page Giter Site logo

incremental's Introduction

Incremental ๐Ÿ“ˆ

Incremental Deterministic Decimal Number type in C#

Features

  • 128-bit number type
    • 1-bit sign
    • 57-bit mantissa
    • 64-bit exponent
  • Decimal representation (No binary rounding error)
  • Deterministic math calculation
  • Reasonable precision (17 decimal digits)
  • HUGE representation range from 1E-(2^63) to 9.99E+(2^63-1)
    • Means you can have 9,223,372,036,854,775,807 zeros

Installation

Clone this repository and copy cs files under Incremental folder to your project.

Comparison

Category Incremental C# decimal BreakInfinity BigDouble
Size 16 bytes (long+long) 16 bytes 16 bytes (double+long)
Representation decimal (base 10) decimal (base 10) binary (base 2)
Deterministic? Yes Yes No
Precision 17 digits 28~29 digits 15~17 digits
Exponent (Up to) 64 bits (E+2^63-1) 8 bits (E+28) 64+11 bits (E+2^63-1+308)

Since Incremental uses decimal representation, you are able to write exact number as 0.1, which is actually 0.1000000000000000055511151231257827021181583404541015625 when you write in double type. Due to this behaviour, Incremental does not suffer from binary rounding errors. It would be a better choice when you want to use same type for incremental currencies and regular ones.

Incremental also support deterministic calculation across platforms. For example, you could use it for input-synced lockstep scenario with incremental stats.

Overall, you should consider using Incremental when you want very big number with decimal places and/or deterministic behaviour.

Benchmarks

You can see the benchmark results in Incremental.Benchmarks.

Implementation Details

Data

Incremental type has two long variable, Mantissa and Exponent.

Mantissa is normalized decimal representation of fixed point number where 10,000,000,000,000,000 (or Unit) is 1 and 99,990,000,000,000,000 is 9.999. Mantissa is signed and can represent negative number. Absolute value of Mantissa is always Unit <= x < Unit * 10, except when it is 0.

Exponent is power of 10 value to multiply Mantissa. Exponent is signed and can represent smaller value than 1.

Multiplication

128-bit math is not native in 64-bit system, Incremental does partial multiplication.

For multiplication, the result mantissa would be a * b / Unit. Since result of a * b will overflow in 64-bit size, Incremental has to calculate a / Unit first then multiply by b.

We can represent a fractal part of 1 / Unit (0x0.000...734ACA5F6226F0ADA6...), then by shifting it left to remove leading zeros for precision. Then we get magic number 0xE69594BEC44DE15B which is (1 / Unit) << 53 << 64.

We can remove unused bit of a's mantissa with shifting it's value left by 7 bits, then multiply with magic number. The full result will be 128-bit, but we are only need to calculate upper 64-bit since the result is already shifted. Taking upper half would be same as shift total result to right by 64, so the result is (a / Unit) << 60.

As same as earlier, we can shift b by 7 bits, multiply with the previous result then take the upper 64-bit. The result is (a / Unit * b) << 3, so by shifting 3 bits to right we can get the final result.

The procedural is fast because only multiplication is involved. It is similar to what compiler does to optimize division. Further reading: Explanation on StackOverflow

Division

As same reason as multiplication, we have to do partial division. However partial division is not simple as multiplication, we cannot simply choose to take upper bit and divide.

While other algorithm is required for full division of 128-bit dividend and 64-bit divisor, Using some unused bits of Incremental data type, we can calculate the quotient with multiple 64-bit division.

By removing leading zero of dividend and trailing zeros of divisor, we can do partial division and get intermediate quotient. Shift 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.

Finally, doing multiplication between binary quotient and Unit, we can get normalized mantissa of the quotient.

incremental's People

Contributors

cathei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

doug-w

incremental's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.