Skip to content

libj/math

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LibJ Math

Build Status Coverage Status Javadocs Released Version Snapshot Version

Introduction

LibJ Math is an extension to the java.math Java API. The classes in LibJ Math can be split in two categories:

  1. Higher-performance alternatives to functionalities present in java.math.
  2. Supplementary functionalities missing in java.math.

Higher-performance alternatives

BigInt

Introduction

An arbitrary-precision integer replacement for java.math.BigInteger, with the following differences:

  1. Mutable: BigInt is mutable, allowing for reuse of allocated magnitude arrays.
  2. Little-endian: BigInt's magnitude array is in little-endian order, allowing for faster operations concerning changes to a number's scale.
  3. Faster arithmetic: The arithmetic algorithms in BigInt are implemented with the optimization of memory (heap allocation) and runtime performance in mind.
  4. Faster multiplication of large numbers: Support parallel multiplication algorithm for large numbers.
  5. In-place multiplication algorithms: Employs optimized algorithms that perform calculations in place, rather than instantiating transient magnitude arrays to defer to the GC to free later.
  6. Support for int and long parameters and return types: BigInt does not require its parameters or return types to be BigInt, avoiding unnecessary instantiation of transient BigInt objects and int[] arrays.
  7. Support for "object-less" operation: All methods in BigInt are available in static form, allowing bare int[] value-encoded number arrays to be used without a BigInt instance, leading to further reduction in heap memory allocation.
  8. Significantly reduced heap allocation: BigInt was designed to reduce the number of instances allocated purely for the purpose of transient calculation, and significantly outperforms BigInteger with regard to memory and GC load.
  9. No preemptive exception checking: BigInt does not preemptively check for exceptions. If a programmer divides by zero he has only himself to blame. And, it is ok to have undefined behavior.
  10. Native bindings: BigInt provides select algorithms in 3 forms:
    1. JNI: Critical Native JNI integration for fastest performance, with minimal function overhead.* **
    2. JNI: Java Native JNI integration for faster performance, with regular function overhead.*
    3. JIT: Java Bytecode implementation designed to be optimized by JIT compilation.

* Native Bindings are present in the built JAR for MacOS (x64 and Arm64), Linux (x64), and Windows (x64), and are loaded by default on system startup.
** To use Critical Native JNI bindings, the JVM must be launched with -Xcomp.

Bare int[] value-encoded number arrays

The BigInt architecture exposes the underlying int[] array, and provides static function equivalents for all of its instance methods. This is possible because the standalone int[] array contains all information regarding the magnitude of an arbitrary precision integer. The int[] has the following encoding:

  • Signed length: The sign and number of base-232 digits (limbs) in the magnitude.
    val[0][-1 << 26, .., -1, 0, 1, .., 1 << 26]
  • Absolute length: The absolute number of base-232 digits (limbs) in the magnitude.
    Math.abs(val[0])
  • Sign: The sign of the magnitude (-1 for negative, and 1 for positive).
    Math.signum(val[0])
  • Zero: Magnitude is zero.
    val[0] == 0
  • Magnitude digits: The base-232 digits (limbs).
    val[2,val[0]-1][Integer.MIN_VALUE, Integer.MAX_VALUE]
  • The base 232 digits (limbs) of the number are in little-endian order.

The bare int[] array can therefore be used as a feature-equivalent replacement for BigInt, with one notable difference: no BigInt instance is required.

Getting Started

BigInt is bundled with this module, which is available in the Maven Central Repository. The BigInt implementation provides JNI bindings for MacOS (x64 and Arm64), Linux and Windows platforms (x64), which can improve performance significantly. The JNI bindings are activated automatically, unless -Dorg.libj.math.BigInt.noNative is specified as a system property. The JNI bindings were built with Intel compilers, and are as statically linked as can be. The bindings also rely on the following shared libraries:

Prerequisites
  1. Linux: libcilkrts5
  2. MacOS: None
  3. Windows: None

Function Matrix

The following matrix provides a comparison of functions offered by BigInteger vs BigInt and bare int[] array. The values in the matrix have the following rules:

  1. 0: Represents the baseline.
  2. +###%: Prepresents "percent better* compared to the baseline".
       * "Better" means: 'faster' for runtime performance, and 'less instances' for heap memory allocation.

It is also important to note the following:

  • These numbers are derived from the detailed benchmark tests that are linked on each row. Please refer to Benchmarks for further information.
  • These numbers have an error margin, and should be considered as estimates. It is possible to achieve better precision in the results, but would require significant time running these tests in order to increase the sample size.
  • For functions that are not inherently available in the particular subject (i.e. in BigInteger), external utility functions were used to bridge the gap.

                  Runtime Performance                               Heap Allocation             ╔════════════════════╦════════════╦═════════╦═════════╗  ╔════════════╦══════════╦══════════╗   ║                    ║ BigInteger ║ BigInt  ║  int[]  ║  ║ BigInteger ║  BigInt  ║  int[]   ║   ╠════════════════════╬════════════╬═════════╬═════════╣  ╠════════════╬══════════╬══════════╣   ║       add(int,int) ║          0 ║   +117% ║   +112% ║  ║          0 ║    +191% ║    +113% ║  
║           add(int) ║          0 ║   +191% ║   +363% ║  ║          0 ║    +191% ║    +113% ║  
║      add(int,long) ║          0 ║   +203% ║   +139% ║  ║          0 ║    +297% ║    +208% ║  
║          add(long) ║          0 ║    +87% ║   +230% ║  ║          0 ║    +197% ║    +126% ║  
║             add(T) ║          0 ║    +10% ║    +87% ║  ║          0 ║     +75% ║     +33% ║  
║       sub(int,int) ║          0 ║   +111% ║   +172% ║  ║          0 ║    +191% ║    +113% ║  
║           sub(int) ║          0 ║   +151% ║   +392% ║  ║          0 ║    +191% ║    +113% ║  
║      sub(int,long) ║          0 ║   +253% ║   +285% ║  ║          0 ║    +297% ║    +208% ║  
║          sub(long) ║          0 ║   +183% ║   +203% ║  ║          0 ║    +197% ║    +126% ║  
║             sub(T) ║          0 ║     +8% ║    +55% ║  ║          0 ║     +75% ║     +33% ║  
║              not() ║          0 ║   +645% ║  +1173% ║  ║          0 ║    +113% ║     +38% ║  
║             xor(T) ║          0 ║   +236% ║   +461% ║  ║          0 ║     +76% ║     +34% ║  
║              or(T) ║          0 ║   +332% ║   +453% ║  ║          0 ║     +85% ║     +43% ║  
║             and(T) ║          0 ║   +384% ║   +455% ║  ║          0 ║     +75% ║     +33% ║  
║          andNot(T) ║          0 ║   +353% ║   +511% ║  ║          0 ║     +75% ║     +33% ║  
║         bitCount() ║        +7% ║       0 ║    +88% ║  ║       +50% ║     +50% ║        0 ║  
║        bitLength() ║          0 ║    +47% ║    +72% ║  ║          0 ║     +80% ║    +210% ║  
║   toByteArray() BE ║          0 ║    +36% ║    +14% ║  ║       +50% ║     +50% ║        0 ║  
║   toByteArray() LE ║          0 ║    +89% ║    +96% ║  ║       +50% ║     +50% ║        0 ║  
║       testBit(int) ║        +8% ║    +31% ║    +13% ║  ║       +50% ║     +50% ║        0 ║  
║        setBit(int) ║          0 ║   +492% ║   +619% ║  ║          0 ║    +111% ║     +36% ║  
║       flipBit(int) ║          0 ║   +400% ║   +460% ║  ║          0 ║    +111% ║     +36% ║  
║      clearBit(int) ║          0 ║   +375% ║   +438% ║  ║          0 ║    +111% ║     +36% ║  
║     shiftLeft(int) ║       +30% ║     +2% ║    +59% ║  ║          0 ║    +100% ║     +25% ║  
║    shiftRight(int) ║          0 ║    +59% ║   +102% ║  ║          0 ║    +100% ║     +25% ║  
║       div(int,int) ║          0 ║    +84% ║   +109% ║  ║          0 ║    +142% ║     +72% ║  
║      div(int,long) ║          0 ║   +180% ║   +142% ║  ║          0 ║    +247% ║    +158% ║  
║           div(int) ║          0 ║   +135% ║   +153% ║  ║          0 ║    +147% ║     +74% ║  
║          div(long) ║          0 ║   +113% ║   +139% ║  ║          0 ║    +150% ║     +85% ║  
║             div(T) ║          0 ║    +36% ║    +49% ║  ║       +43% ║     +68% ║     +13% ║  
║    divRem(int,int) ║          0 ║    +50% ║    +71% ║  ║          0 ║    +142% ║     +72% ║  
║   divRem(int,long) ║          0 ║   +187% ║   +171% ║  ║          0 ║    +247% ║    +158% ║  
║        divRem(int) ║          0 ║   +125% ║   +136% ║  ║          0 ║    +147% ║     +74% ║  
║       divRem(long) ║          0 ║   +133% ║   +143% ║  ║          0 ║    +150% ║     +85% ║  
║          divRem(T) ║          0 ║     +2% ║    +13% ║  ║       +50% ║     +28% ║      +9% ║  
║          log10(UP) ║          0 ║  +5553% ║ +10217% ║  ║          0 ║    +618% ║    +334% ║  
║        log10(DOWN) ║          0 ║  +7531% ║ +10869% ║  ║          0 ║    +618% ║    +334% ║  
║       log10(FLOOR) ║          0 ║  +8085% ║ +10956% ║  ║          0 ║    +611% ║    +329% ║  
║     log10(CEILING) ║          0 ║  +7724% ║ +10177% ║  ║          0 ║    +615% ║    +331% ║  
║     log10(HALF_UP) ║          0 ║  +8733% ║ +11200% ║  ║          0 ║    +863% ║    +497% ║  
║   log10(HALF_DOWN) ║          0 ║  +8846% ║ +11706% ║  ║          0 ║    +874% ║    +504% ║  
║   log10(HALF_EVEN) ║          0 ║  +7972% ║ +10026% ║  ║          0 ║    +874% ║    +504% ║  
║ log10(UNNECESSARY) ║          0 ║ +11783% ║ +17292% ║  ║          0 ║    +624% ║    +338% ║  
║           log2(UP) ║          0 ║  +7632% ║  +9239% ║  ║       +50% ║    +250% ║    +100% ║  
║         log2(DOWN) ║          0 ║ +18591% ║ +19961% ║  ║       +50% ║    +250% ║    +100% ║  
║        log2(FLOOR) ║          0 ║ +16631% ║ +18523% ║  ║       +50% ║    +250% ║    +100% ║  
║      log2(CEILING) ║          0 ║  +7722% ║  +9174% ║  ║       +50% ║    +245% ║     +97% ║  
║      log2(HALF_UP) ║          0 ║  +7455% ║  +8727% ║  ║        +5% ║    +295% ║    +122% ║  
║    log2(HALF_DOWN) ║          0 ║  +7574% ║  +8423% ║  ║          0 ║    +295% ║    +122% ║  
║    log2(HALF_EVEN) ║          0 ║  +6996% ║  +8522% ║  ║        +5% ║    +286% ║    +118% ║  
║  log2(UNNECESSARY) ║          0 ║ +28168% ║ +34450% ║  ║       +50% ║    +250% ║    +100% ║  
║          log(DOWN) ║          0 ║    +82% ║   +105% ║  ║       +50% ║     +50% ║        0 ║  
║            log(UP) ║          0 ║    +29% ║    +28% ║  ║       +50% ║     +50% ║        0 ║  
║         log(FLOOR) ║          0 ║    +19% ║     +9% ║  ║       +50% ║     +50% ║        0 ║  
║       log(CEILING) ║          0 ║    +37% ║    +26% ║  ║       +50% ║     +50% ║        0 ║  
║       log(HALF_UP) ║          0 ║    +26% ║    +22% ║  ║       +50% ║     +50% ║        0 ║  
║     log(HALF_DOWN) ║          0 ║    +25% ║    +20% ║  ║       +50% ║     +50% ║        0 ║  
║     log(HALF_EVEN) ║          0 ║    +33% ║    +21% ║  ║       +50% ║     +50% ║        0 ║  
║   log(UNNECESSARY) ║          0 ║    +20% ║    +32% ║  ║       +50% ║     +50% ║        0 ║  
║               sqrt ║          0 ║   +300% ║   +372% ║  ║            ║          ║          ║  
║          mul(T): 1 ║        +9% ║       0 ║    +53% ║  ║       +41% ║     +75% ║     +12% ║  
║          mul(T): 2 ║          0 ║     +2% ║    +21% ║  ║       +45% ║     +75% ║     +12% ║  
║          mul(T): 4 ║       +30% ║       0 ║     +7% ║  ║       +45% ║     +75% ║     +12% ║  
║          mul(T): 8 ║       +89% ║       0 ║     +2% ║  ║       +50% ║     +75% ║     +12% ║  
║         mul(T): 16 ║      +116% ║       0 ║     +4% ║  ║       +18% ║    +102% ║     +26% ║  
║         mul(T): 32 ║       +86% ║       0 ║     +4% ║  ║          0 ║    +531% ║    +300% ║  
║         mul(T): 64 ║       +54% ║       0 ║     +3% ║  ║          0 ║   +2065% ║   +1303% ║  
║        mul(T): 128 ║       +40% ║       0 ║     +3% ║  ║          0 ║   +8491% ║   +5508% ║  
║        mul(T): 256 ║          0 ║     +3% ║     +8% ║  ║          0 ║  +23570% ║  +15365% ║  
║        mul(T): 512 ║          0 ║     +9% ║    +17% ║  ║          0 ║  +61184% ║  +39956% ║  
║       mul(T): 1024 ║          0 ║    +42% ║    +46% ║  ║          0 ║ +192303% ║ +125677% ║  
║           pow(int) ║       +65% ║       0 ║     +4% ║  ║          0 ║    +902% ║    +162% ║  
║       mul(int,int) ║          0 ║    +38% ║    +98% ║  ║          0 ║    +175% ║     +75% ║  
║           mul(int) ║          0 ║    +80% ║   +167% ║  ║          0 ║    +175% ║     +75% ║  
║      mul(int,long) ║          0 ║   +143% ║   +193% ║  ║          0 ║    +250% ║    +125% ║  
║          mul(long) ║          0 ║    +44% ║    +83% ║  ║          0 ║    +165% ║     +65% ║  
║        mul(T,T): 1 ║       +12% ║       0 ║     +4% ║  ║       +34% ║    +100% ║     +25% ║  
║        mul(T,T): 2 ║       +22% ║       0 ║     +4% ║  ║       +41% ║    +100% ║     +25% ║  
║        mul(T,T): 4 ║       +47% ║       0 ║     +6% ║  ║       +34% ║    +100% ║     +25% ║  
║        mul(T,T): 8 ║       +88% ║       0 ║     +3% ║  ║       +14% ║    +100% ║     +25% ║  
║       mul(T,T): 16 ║      +111% ║       0 ║     +1% ║  ║        +7% ║    +100% ║     +25% ║  
║       mul(T,T): 32 ║       +96% ║       0 ║     +1% ║  ║          0 ║    +411% ║    +231% ║  
║       mul(T,T): 64 ║       +81% ║       0 ║       0 ║  ║          0 ║   +1997% ║   +1295% ║  
║      mul(T,T): 128 ║       +76% ║       0 ║     +2% ║  ║          0 ║   +6515% ║   +4313% ║  
║      mul(T,T): 256 ║       +11% ║       0 ║     +5% ║  ║          0 ║  +17440% ║  +11624% ║  
║      mul(T,T): 512 ║          0 ║     +2% ║     +9% ║  ║          0 ║  +49977% ║  +33377% ║  
║     mul(T,T): 1024 ║          0 ║    +57% ║    +62% ║  ║          0 ║ +149643% ║ +100036% ║  
║              neg() ║          0 ║   +231% ║   +223% ║  ║       +50% ║    +100% ║     +25% ║  
║              abs() ║          0 ║   +126% ║   +118% ║  ║       +50% ║     +72% ║     +11% ║  
║        byteValue() ║          0 ║    +40% ║   +102% ║  ║       +50% ║     +50% ║        0 ║  
║       shortValue() ║       +24% ║       0 ║    +81% ║  ║       +50% ║     +50% ║        0 ║  
║         intValue() ║       +71% ║       0 ║   +268% ║  ║       +50% ║     +50% ║        0 ║  
║        longValue() ║          0 ║    +90% ║   +106% ║  ║       +50% ║     +50% ║        0 ║  
║       floatValue() ║       +40% ║       0 ║    +78% ║  ║       +50% ║     +50% ║        0 ║  
║      doubleValue() ║          0 ║    +23% ║    +39% ║  ║       +50% ║     +50% ║        0 ║  
║         toString() ║          0 ║   +356% ║   +366% ║  ║      +100% ║    +427% ║    +109% ║  
║         hashCode() ║        +4% ║     +4% ║       0 ║  ║       +50% ║     +50% ║        0 ║  
║           signum() ║          0 ║     +3% ║    +50% ║  ║       +50% ║     +50% ║        0 ║  
║        precision() ║          0 ║  +1922% ║  +2466% ║  ║          0 ║    +745% ║    +445% ║  
║       compareTo(T) ║       +23% ║       0 ║    +25% ║  ║       +25% ║     +50% ║     +16% ║  
║          equals(T) ║          0 ║    +12% ║    +33% ║  ║       +25% ║     +50% ║     +16% ║  
║             max(T) ║        +6% ║       0 ║    +41% ║  ║       +25% ║     +50% ║     +16% ║  
║             min(T) ║       +16% ║       0 ║    +31% ║  ║       +25% ║     +50% ║     +16% ║  
║       rem(int,int) ║          0 ║   +135% ║   +123% ║  ║          0 ║    +183% ║     +97% ║  
║     rem(int,int):T ║          0 ║    +62% ║   +109% ║  ║          0 ║    +161% ║     +83% ║  
║      rem(int,long) ║          0 ║   +198% ║   +207% ║  ║          0 ║    +274% ║    +176% ║  
║    rem(int,long):T ║          0 ║   +200% ║   +184% ║  ║          0 ║    +247% ║    +158% ║  
║           rem(int) ║          0 ║   +174% ║   +146% ║  ║          0 ║    +161% ║     +83% ║  
║         rem(int):T ║          0 ║   +165% ║   +135% ║  ║          0 ║    +161% ║     +83% ║  
║          rem(long) ║          0 ║   +140% ║   +111% ║  ║          0 ║    +164% ║     +93% ║  
║        rem(long):T ║          0 ║   +136% ║   +149% ║  ║          0 ║    +164% ║     +93% ║  
║             rem(T) ║          0 ║    +54% ║    +69% ║  ║       +25% ║     +75% ║     +33% ║  
║           mod(int) ║          0 ║   +182% ║   +227% ║  ║          0 ║    +197% ║    +111% ║  
║          mod(long) ║          0 ║   +161% ║   +182% ║  ║          0 ║    +201% ║    +123% ║  
║             mod(T) ║          0 ║    +58% ║    +79% ║  ║       +11% ║     +86% ║     +40% ║  
║         sqrt(DOWN) ║          0 ║   +651% ║   +973% ║  ║          0 ║    +497% ║    +141% ║  
║           sqrt(UP) ║          0 ║   +700% ║   +868% ║  ║          0 ║    +516% ║    +145% ║  
║        sqrt(FLOOR) ║          0 ║   +758% ║   +946% ║  ║          0 ║    +494% ║    +141% ║  
║      sqrt(CEILING) ║          0 ║   +686% ║   +855% ║  ║          0 ║    +522% ║    +153% ║  
║      sqrt(HALF_UP) ║          0 ║   +569% ║   +704% ║  ║          0 ║    +610% ║    +198% ║  
║    sqrt(HALF_DOWN) ║          0 ║   +671% ║   +865% ║  ║          0 ║    +622% ║    +204% ║  
║    sqrt(HALF_EVEN) ║          0 ║   +675% ║   +861% ║  ║          0 ║    +632% ║    +208% ║  
║  sqrt(UNNECESSARY) ║          0 ║    +62% ║    +70% ║  ║          0 ║    +544% ║     +68% ║  
╚════════════════════╩════════════╩═════════╩═════════╝  ╚════════════╩══════════╩══════════╝  

Benchmarks

The BigInt implementation is accompanied by a custom test framework that provides:

  1. Assert correctness of function results
    The results of each test are asserted to be equal amongst all test subjects.

  2. Compare runtime performance
    The custom test framework provides a mechanism for the isolation of a specific method to be tested. The actual tests are thus written to compare the feature-equivalent contextually appropriate function that is intended to be benchmarked.

  3. Compare heap memory allocation
    The custom test framework detects how many instances of a particular type are created during the execution of a test. This is accomplished with bytecode instrumentation via the Byteman and ByteBuddy instrumentation agents. The instrumentation enables a callback to be invoked after the instantiation of the types: BigInteger, BigInt, and int[].

The custom test framework achieves (2) and (3) with a "phased execution" approach, whereby the runtime performance is evaluated first, afterwhich the runtime is instrumented for the evaluation of the heap memory allocations in a repeated execution. It is necessary to evaluate the runtime performance before instrumentation, because instrumentation adds significant overhead to the runtime.

The following section provides benchmarks that compare the performance of BigInteger, BigInt, and bare int[] value-encoded number arrays.

The benchmark results provide runtime and memory heap allocation performance comparisons in the following kinds of tables and charts:

  1. Summary of runtime performance

    This table shows the relative performance of each function tested in the relevant test class (BigIntAdditionTest, BigIntMultiplicationTest, etc.). The values in this table represent the "percent less time spent in the function being tested", as compared to the baseline, which is the test subject (BigInteger, BigInt, or int[]) containing the 0 value (i.e. that test subject spends 0% less time than the baseline (itself) for the test).

runtime summary

  1. Summary of heap memory allocation

    This table shows the relative heap allocation performance of each function tested in the relevant test class (BigIntAdditionTest, BigIntMultiplicationTest, etc.). The values in this table represent the "percent less number of instances allocated on the heap during the execution of the function being tested", as compared to the baseline, which is the test subject (BigInteger, BigInt, or int[]) containing the 0 value (i.e. that test subject allocates 0% less instances than the baseline (itself) for the test). The columns for heap allocation results provide 2 values: T and int[]. Here, T represents the type of the test subject (BigInteger, BigInt, or int[]), and int[] represents the int[] type itself, as both BigInteger and BigInt use int[] as the underlying representation of the number's magnitude. Therefore, for bare int[] value-encoded number arrays, T and int[] refer to the same thing.

heap summary

  1. Detailed runtime performance

    This table provides a detailed view of the runtime performance test results as delineated by the precision of the input(s) being tested. This table shows 3 meta-columns:

        a. Length: The length of the underlying int[] (i.e. int[].length).
        b. Precision: The precision (number of digits) of the number -- positive precision is for positive values, and negative precision is for negative values.
        c. Count: Number of tests that were run.

    The values in the columns of the test subject (BigInteger, BigInt, or int[]) represent the mean time spent (nanoseconds) in the test method. If the test method being tested applies to one input (like BigInteger.abs(), where the one input is this), then the table will provide a single mean time spent value. If the test method being tested applies to two inputs (like BigInteger.add(BigInteger), where the first input is this and the second is some other BigInteger instance), then the table will provide two mean time spent values -- one for each input. This feature of the test framework allows one to more easily identify performance discrepancies between "when a particular value of a particular precision is the first argument vs if it's the second argument".

    The table provides 2 additional rows at the bottom:
        a. Sum: The sum of the mean time spent in all precision sections.
        a. +%: The relative improvement in performance, as represented by the "percent less time spent in the function being tested" by evaluating the sum mean time spent in all precision sections. Like in the table for the Summary of runtime performance, this percentage is compared to the baseline, which is the test subject (BigInteger, BigInt, or int[]) containing the 0 value (i.e. that test subject spends 0% less time than the baseline (itself) for the test).

runtime

  1. Runtime performance chart

    This chart provides a visual representation of the Detailed runtime performance table. Note that the y values are inverted, whereby the higher y values in the graph are better than lower.

chart

  1. Detailed heap memory alloction

    This table provides a detailed view of the heap memory alloction test results as delineated by the precision of the input(s) being tested. This table shows 3 meta-columns:

        a. Length: The length of the underlying int[] (i.e. int[].length).
        b. Precision: The precision (number of digits) of the number -- positive precision is for positive values, and negative precision is for negative values.
        c. Count: Number of tests that were run.

    The values in the columns of the test subject (BigInteger, BigInt, or int[]) represent the total number of instances allocated during the execution of the tested function. Like in the table for the Summary of heap memory allocation, the columns for heap allocation results provide 2 values: T and int[]. Here, T represents the type of the test subject (BigInteger, BigInt, or int[]), and int[] represents the int[] type itself, as both BigInteger and BigInt use int[] as the underlying representation of the number's magnitude. Therefore, for bare int[] value-encoded number arrays, T and int[] refer to the same thing.

    The table provides 2 additional rows at the bottom:
        a. Sum: The sum of the total number of instances in all precision sections.
        a. +%: The relative improvement in performance, as represented by the "percent less number of instances allocated on the heap during the execution of the function being tested" by evaluating the sum total number of instances in all precision sections. Like in the table for the Summary of heap memory allocation, this percentage is compared to the baseline, which is the test subject (BigInteger, BigInt, or int[]) containing the 0 value (i.e. that test subject allocates 0% less instances than the baseline (itself) for the test). Similarly, the columns for heap allocation results provide 2 values: T and int[]. Here, T represents the type of the test subject (BigInteger, BigInt, or int[]), and int[] represents the int[] type itself, as both BigInteger and BigInt use int[] as the underlying representation of the number's magnitude. Therefore, for bare int[] value-encoded number arrays, T and int[] refer to the same thing.

heap

Benchmark Results

  • All tests were run with Java 1.8.0_231 on Mac OS 10.15.6.
  • All tests were run with -Xcomp argument, for precompilation of JIT optimizations.
  • All tests were run with Critical Native bindings loaded, which automatically happens when -Xcomp is present on the JVM argument list.

Benchmark tests are organized in 8 test classes, each responsible for its context of functions:

Link to results Link to test code
Addition and subtraction BigIntAdditionTest
Multiplication BigIntMultiplicationTest
Division BigIntDivisionTest
Remainder and modulus BigIntRemainderTest
Binary operations BigIntBinaryTest
Bitwise operations BigIntBitwiseTest
Predicate functions BigIntPredicateTest
Constructors BigIntConstructorTest

FAQ

  1. Is BigInt error free?

    With respect to the correctness of its algorithms, BigInt has a custom test framework specifically designed to test the full breadth and adjustable depth of inputs into its algorithms. The test framework separates test inputs into "special" and "random". Special inputs are those that involve numbers representing special edges insofar as the number's int encoding, or the result of operations leading to propagating carrys. Random inputs are generated on a "breadth first" basis with respect to the input's decimal precision, allowing the depth (testing of more random values for a single precision) to be adjustable for the purposes of development vs comprehensive analysis.

    With respect to exception checking, the BigInt does not preemptively check for exceptions. If a programmer divides by zero he has only himself to blame. And, it is ok to have undefined behavior.

  2. What is BigInt's biggest advantage?

    BigInt was created for one specific purpose: to lower the heap memory allocations for regular arithmetic operations. BigInteger liberally creates transient instances for the purpose of calculations, which results in a significant memory load and subsequent runtime performance load when the GC turns on. This situation is particularly relevant in applications that work with very many instances of arbitrary precision numbers. An example of such an application is an Asset Trading Systems (Level 3) that consumes live streams of order data. Arbitrary precision arithmetic is necessary for Asset Trading Systems in lieu of the need for fixed point arithmetic.

    See Decimal.

  3. What is BigInt's biggest disadvantage?

    Though BigInt outperforms BigInteger in most operations, there are a few in which it is lacking. One particular operation that is important to note is mul(T) (i.e. multiplication of an arbitrary precision number by another arbitrary precision number). BigInt's mul(T) cannot match the performance of BigInteger's multiply(T) for "medium-sized numbers", because BigInteger's multiply(T) is implemented as an intrinsic function. BigInt comes close to this performance with its Critical Native implementation of its multiplication algorithms, but it is still not as fast. Nonetheless, where BigInt loses in isolated runtime performance, it gains back with its superior ability in reducing unnecessary heap memory allocation for transient calculations.

    Please refer to Multiplication for benchmark statistics.

  4. What is Critical Native JNI?

    Calling a JNI method from Java is rather expensive compared to a simple C function call. Specifically when dealing with arrays, the JNI architecture necessitates expensive operations to convert Java arrays into "critical" native arrays and back. By converting a Java array to a "critical" native array, the JVM is notified to disallow the GC from freeing the respective memory. This overhead is significant, and all but disqualifies JNI as an optimization for algorithms that work with arrays.

    The JDK has a private API called Critical Native to reduce the overhead function calls that do not require much JNI functionality. This feature was designed for internal use in the JDK. There is no public specification, and the only documentation you may find is in the comments to JDK-7013347.

    For BigInt, the use of Critical Native JNI results in ~25% faster performance invoking JNI functions.

    For further information about Critical Native JNI, please refer to this StackOverflow post.

Decimal

Introduction

A 64-bit precision decimal alternative to java.math.BigDecimal, with the following differences:

  1. Avoids Heap Allocation: The Decimal represents a fixed-point number inside a long primitive, thus limiting the precision of a Decimal-encoded number to 64 bits, and eliminating the cost of heap allocation entirely. Please refer to Long Encoding for further details on Decimal's 64-bit Precision.
  2. Support for "object-less" operation: All methods in Decimal are available in static form, allowing applications to work solely with long-encoded decimals.
  3. Mutable: Decimal objects are mutable, allowing for reuse of allocated references.
  4. Faster arithmetic: In lieu of Decimal's 64-bit precision limit, many arithmetic operations are faster due to inherent termination thresholds. Similarly, however, Decimal's 64-bit precision limit also demands it to perform precision and scale optimization on each operation, thus resulting in some arithmetic operations to be more expensive. Please refer to Function Matrix for further details on Decimal's performance.
  5. Significantly reduced heap allocation: Decimal was designed to reduce the number of instances allocated purely for the purpose of transient calculation, and significantly outperforms BigDecimal with regard to memory and GC load. When utilizing long-encoded decimals, memory and GC load is reduced to zero.
  6. No preemptive exception checking: Decimal does not preemptively check for exceptions. If a programmer divides by zero he has only himself to blame. And, it is ok to have undefined behavior.

Function Matrix

The following matrix provides a comparison of functions offered by BigDecimal vs Decimal and long-encoded numbers. The values in the matrix have the following rules:

  1. 0: Represents the baseline.
  2. +###%: Prepresents "percent better* compared to the baseline".
       * "Better" means: 'faster' for runtime performance, and 'less instances' for heap memory allocation.

It is also important to note the following:

  • These numbers are derived from the detailed benchmark tests that are linked on each row. Please refer to Benchmarks for further information.
  • These numbers have an error margin, and should be considered as estimates. It is possible to achieve better precision in the results, but would require significant time running these tests in order to increase the sample size.
  • For functions that are not inherently available in the particular subject (i.e. in BigDecimal), external utility functions were used to bridge the gap.

A few other points:

  • Decimal's 64-bit precision limit demands it to perform precision and scale optimization on each operation, thus resulting in some arithmetic operations to be slower than with BigDecimal. This effectively means that for each arithmetic operation, Decimal is also performing a reduced setScale(scale) adjustment to ensure its number can fit in a long-encoded number.
  • Operations on long-encoded numbers are systematically slower than their Decimal equivalents. This is due to the need for the value and scale to be first decoded from a long-encoded number prior to the arithmetic operation. Similarly, the value and scale of the result of the operation need to be then re-encoded into long-encoded number. Though these overhead operations are miniscule, they still do reduce the overall runtime perform of algorithms on long-encoded decimals.
  • The use of the symbol in Heap Allocation stats is due to zero heap allocation for algorithms on long-encoded decimals.

Note: The benchmark results in the following table show arithmetic algorithms specified with a value in parentheses that ranges from 0 (or 3) to 16. This value represents the number of bits reserved for the scale in the long-encoded number representation. Please refer to Long Encoding for further details.

                  Runtime Performance                             Heap Allocation            ╔═════════════════╦════════════╦══════════╦══════════╗  ╔════════════╦═════════╦═════════╗   ║                 ║ BigDecimal ║ Decimal  ║   long   ║  ║ BigDecimal ║ Decimal ║  long   ║   ╠═════════════════╬════════════╬══════════╬══════════╣  ╠════════════╬═════════╬═════════╣   ║          sub(3) ║      +103% ║        0 ║      +3% ║  ║          0 ║    +50% ║       ∞ ║  
║          sub(4) ║       +95% ║        0 ║      +2% ║  ║          0 ║    +50% ║       ∞ ║  
║          sub(5) ║       +62% ║        0 ║      +6% ║  ║          0 ║    +50% ║       ∞ ║  
║          sub(6) ║       +17% ║        0 ║     +10% ║  ║          0 ║    +50% ║       ∞ ║  
║          sub(7) ║          0 ║     +17% ║     +28% ║  ║          0 ║    +50% ║       ∞ ║  
║          sub(8) ║          0 ║     +43% ║     +56% ║  ║          0 ║    +50% ║       ∞ ║  
║          sub(9) ║          0 ║    +153% ║    +176% ║  ║          0 ║    +50% ║       ∞ ║  
║         sub(10) ║          0 ║    +393% ║    +448% ║  ║          0 ║    +50% ║       ∞ ║  
║         sub(11) ║          0 ║    +783% ║    +879% ║  ║          0 ║    +50% ║       ∞ ║  
║         sub(12) ║          0 ║   +1756% ║   +1953% ║  ║          0 ║    +50% ║       ∞ ║  
║         sub(13) ║          0 ║   +5242% ║   +5656% ║  ║          0 ║    +50% ║       ∞ ║  
║         sub(14) ║          0 ║  +15717% ║  +16045% ║  ║          0 ║    +50% ║       ∞ ║  
║         sub(15) ║          0 ║  +38562% ║  +35384% ║  ║          0 ║    +50% ║       ∞ ║  
║         sub(16) ║          0 ║  +89016% ║  +76773% ║  ║          0 ║    +50% ║       ∞ ║  
║          add(3) ║      +171% ║     +52% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          add(4) ║      +156% ║     +48% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          add(5) ║       +90% ║     +38% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          add(6) ║       +28% ║     +37% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          add(7) ║          0 ║     +50% ║      +4% ║  ║          0 ║    +50% ║       ∞ ║  
║          add(8) ║          0 ║     +97% ║     +30% ║  ║          0 ║    +50% ║       ∞ ║  
║          add(9) ║          0 ║    +247% ║    +130% ║  ║          0 ║    +50% ║       ∞ ║  
║         add(10) ║          0 ║    +641% ║    +375% ║  ║          0 ║    +50% ║       ∞ ║  
║         add(11) ║          0 ║   +1242% ║    +748% ║  ║          0 ║    +50% ║       ∞ ║  
║         add(12) ║          0 ║   +2765% ║   +1706% ║  ║          0 ║    +50% ║       ∞ ║  
║         add(13) ║          0 ║   +7919% ║   +5039% ║  ║          0 ║    +50% ║       ∞ ║  
║         add(14) ║          0 ║  +23627% ║  +14658% ║  ║          0 ║    +50% ║       ∞ ║  
║         add(15) ║          0 ║  +61436% ║  +37517% ║  ║          0 ║    +50% ║       ∞ ║  
║         add(16) ║          0 ║ +136900% ║  +81121% ║  ║          0 ║    +50% ║       ∞ ║  
║          div(3) ║          0 ║     +94% ║     +80% ║  ║          0 ║    +50% ║       ∞ ║  
║          div(4) ║          0 ║     +87% ║     +74% ║  ║          0 ║    +50% ║       ∞ ║  
║          div(5) ║          0 ║     +90% ║     +80% ║  ║          0 ║    +50% ║       ∞ ║  
║          div(6) ║          0 ║     +93% ║     +87% ║  ║          0 ║    +50% ║       ∞ ║  
║          div(7) ║          0 ║     +91% ║     +90% ║  ║          0 ║    +50% ║       ∞ ║  
║          div(8) ║          0 ║     +90% ║     +89% ║  ║          0 ║    +50% ║       ∞ ║  
║          div(9) ║          0 ║     +91% ║     +91% ║  ║          0 ║    +50% ║       ∞ ║  
║         div(10) ║          0 ║     +92% ║     +94% ║  ║          0 ║    +50% ║       ∞ ║  
║         div(11) ║          0 ║     +90% ║     +90% ║  ║          0 ║    +50% ║       ∞ ║  
║         div(12) ║          0 ║     +89% ║     +91% ║  ║          0 ║    +50% ║       ∞ ║  
║         div(13) ║          0 ║     +89% ║     +91% ║  ║          0 ║    +50% ║       ∞ ║  
║         div(14) ║          0 ║     +90% ║     +90% ║  ║          0 ║    +50% ║       ∞ ║  
║         div(15) ║          0 ║     +85% ║     +85% ║  ║          0 ║    +50% ║       ∞ ║  
║         div(16) ║          0 ║     +82% ║     +81% ║  ║          0 ║    +50% ║       ∞ ║  
║          rem(3) ║          0 ║    +848% ║    +497% ║  ║          0 ║   +172% ║       ∞ ║  
║          rem(4) ║          0 ║    +754% ║    +476% ║  ║          0 ║   +168% ║       ∞ ║  
║          rem(5) ║          0 ║    +614% ║    +423% ║  ║          0 ║   +168% ║       ∞ ║  
║          rem(6) ║          0 ║    +803% ║    +633% ║  ║          0 ║   +172% ║       ∞ ║  
║          rem(7) ║          0 ║   +1369% ║   +1107% ║  ║          0 ║   +177% ║       ∞ ║  
║          rem(8) ║          0 ║   +1969% ║   +1595% ║  ║          0 ║   +177% ║       ∞ ║  
║          rem(9) ║          0 ║   +2441% ║   +1929% ║  ║          0 ║   +177% ║       ∞ ║  
║         rem(10) ║          0 ║   +2754% ║   +2165% ║  ║          0 ║   +177% ║       ∞ ║  
║         rem(11) ║          0 ║   +3003% ║   +2306% ║  ║          0 ║   +177% ║       ∞ ║  
║         rem(12) ║          0 ║   +3116% ║   +2351% ║  ║          0 ║   +177% ║       ∞ ║  
║         rem(13) ║          0 ║   +3187% ║   +2383% ║  ║          0 ║   +177% ║       ∞ ║  
║         rem(14) ║          0 ║   +3191% ║   +2440% ║  ║          0 ║   +177% ║       ∞ ║  
║         rem(15) ║          0 ║   +3285% ║   +2416% ║  ║          0 ║   +177% ║       ∞ ║  
║         rem(16) ║          0 ║   +3306% ║   +2419% ║  ║          0 ║   +177% ║       ∞ ║  
║          mul(3) ║       +78% ║     +11% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          mul(4) ║       +86% ║     +16% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          mul(5) ║       +93% ║     +19% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          mul(6) ║       +96% ║     +19% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          mul(7) ║       +92% ║     +22% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          mul(8) ║       +91% ║     +24% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║          mul(9) ║       +95% ║     +26% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║         mul(10) ║       +95% ║     +26% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║         mul(11) ║      +102% ║     +31% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║         mul(12) ║      +103% ║     +33% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║         mul(13) ║      +105% ║     +34% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║         mul(14) ║      +102% ║     +40% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║         mul(15) ║      +104% ║     +43% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║         mul(16) ║      +113% ║     +41% ║        0 ║  ║          0 ║    +50% ║       ∞ ║  
║           eq(3) ║       +55% ║        0 ║    +143% ║  ║          0 ║       0 ║       0 ║  
║           eq(4) ║       +38% ║        0 ║    +117% ║  ║          0 ║       0 ║       0 ║  
║           eq(5) ║       +63% ║        0 ║    +162% ║  ║          0 ║       0 ║       0 ║  
║           eq(6) ║       +61% ║        0 ║    +146% ║  ║          0 ║       0 ║       0 ║  
║           eq(7) ║       +57% ║        0 ║    +119% ║  ║          0 ║       0 ║       0 ║  
║           eq(8) ║       +64% ║        0 ║    +140% ║  ║          0 ║       0 ║       0 ║  
║           eq(9) ║       +59% ║        0 ║    +139% ║  ║          0 ║       0 ║       0 ║  
║          eq(10) ║       +67% ║        0 ║    +145% ║  ║          0 ║       0 ║       0 ║  
║          eq(11) ║       +61% ║        0 ║    +134% ║  ║          0 ║       0 ║       0 ║  
║          eq(12) ║       +49% ║        0 ║    +116% ║  ║          0 ║       0 ║       0 ║  
║          eq(13) ║       +63% ║        0 ║    +126% ║  ║          0 ║       0 ║       0 ║  
║          eq(14) ║       +56% ║        0 ║    +125% ║  ║          0 ║       0 ║       0 ║  
║          eq(15) ║       +65% ║        0 ║    +142% ║  ║          0 ║       0 ║       0 ║  
║          eq(16) ║       +64% ║        0 ║    +140% ║  ║          0 ║       0 ║       0 ║  
║     setScale(3) ║          0 ║    +326% ║    +264% ║  ║          0 ║   +100% ║       ∞ ║  
║     setScale(4) ║          0 ║    +342% ║    +279% ║  ║          0 ║   +100% ║       ∞ ║  
║     setScale(5) ║          0 ║    +298% ║    +268% ║  ║          0 ║   +100% ║       ∞ ║  
║     setScale(6) ║          0 ║    +291% ║    +275% ║  ║          0 ║   +100% ║       ∞ ║  
║     setScale(7) ║          0 ║    +313% ║    +281% ║  ║          0 ║   +100% ║       ∞ ║  
║     setScale(8) ║          0 ║    +292% ║    +270% ║  ║          0 ║   +100% ║       ∞ ║  
║     setScale(9) ║          0 ║    +484% ║    +450% ║  ║          0 ║   +100% ║       ∞ ║  
║    setScale(10) ║          0 ║   +1696% ║   +1596% ║  ║          0 ║   +100% ║       ∞ ║  
║    setScale(11) ║          0 ║   +3300% ║   +3203% ║  ║          0 ║   +100% ║       ∞ ║  
║    setScale(12) ║          0 ║   +6336% ║   +6336% ║  ║          0 ║   +100% ║       ∞ ║  
║    setScale(13) ║          0 ║  +16051% ║  +16314% ║  ║          0 ║   +100% ║       ∞ ║  
║    setScale(14) ║          0 ║  +49593% ║  +51742% ║  ║          0 ║   +100% ║       ∞ ║  
║    setScale(15) ║          0 ║ +140003% ║ +143240% ║  ║          0 ║   +100% ║       ∞ ║  
║    setScale(16) ║          0 ║ +284765% ║ +296303% ║  ║          0 ║   +100% ║       ∞ ║  
║      compare(3) ║       +56% ║    +156% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      compare(4) ║       +45% ║    +150% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      compare(5) ║       +38% ║    +141% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      compare(6) ║       +32% ║    +154% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      compare(7) ║       +28% ║    +158% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      compare(8) ║       +25% ║    +171% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      compare(9) ║       +24% ║    +175% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     compare(10) ║       +23% ║    +175% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     compare(11) ║       +23% ║    +172% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     compare(12) ║       +26% ║    +171% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     compare(13) ║       +25% ║    +171% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     compare(14) ║       +23% ║    +170% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     compare(15) ║       +28% ║    +165% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     compare(16) ║       +26% ║    +166% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           lt(3) ║       +59% ║    +128% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           lt(4) ║       +48% ║    +131% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           lt(5) ║       +49% ║    +137% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           lt(6) ║       +49% ║    +136% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           lt(7) ║       +51% ║    +144% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           lt(8) ║       +52% ║    +144% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           lt(9) ║       +49% ║    +136% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lt(10) ║       +50% ║    +147% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lt(11) ║       +52% ║    +147% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lt(12) ║       +52% ║    +142% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lt(13) ║       +49% ║    +131% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lt(14) ║       +50% ║    +129% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lt(15) ║       +52% ║    +136% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lt(16) ║       +52% ║    +139% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           gt(3) ║       +52% ║    +115% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           gt(4) ║       +47% ║    +135% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           gt(5) ║       +45% ║    +127% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           gt(6) ║       +46% ║    +134% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           gt(7) ║       +43% ║    +131% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           gt(8) ║       +47% ║    +137% ║        0 ║  ║          0 ║       0 ║       0 ║  
║           gt(9) ║       +46% ║    +144% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gt(10) ║       +44% ║    +132% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gt(11) ║       +45% ║    +128% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gt(12) ║       +45% ║    +131% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gt(13) ║       +46% ║    +131% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gt(14) ║       +45% ║    +140% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gt(15) ║       +42% ║    +124% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gt(16) ║       +46% ║    +125% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lte(3) ║       +97% ║    +191% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lte(4) ║       +88% ║    +193% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lte(5) ║       +82% ║    +182% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lte(6) ║       +83% ║    +192% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lte(7) ║       +82% ║    +196% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lte(8) ║       +82% ║    +182% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          lte(9) ║       +88% ║    +203% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         lte(10) ║       +85% ║    +202% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         lte(11) ║       +82% ║    +149% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         lte(12) ║       +77% ║    +163% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         lte(13) ║       +79% ║    +168% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         lte(14) ║       +82% ║    +175% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         lte(15) ║       +83% ║    +180% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         lte(16) ║       +81% ║    +184% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gte(3) ║       +72% ║    +160% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gte(4) ║       +65% ║    +172% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gte(5) ║       +66% ║    +182% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gte(6) ║       +64% ║    +176% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gte(7) ║       +66% ║    +178% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gte(8) ║       +68% ║    +187% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          gte(9) ║       +67% ║    +187% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         gte(10) ║       +66% ║    +172% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         gte(11) ║       +69% ║    +179% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         gte(12) ║       +68% ║    +181% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         gte(13) ║       +66% ║    +173% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         gte(14) ║       +66% ║    +176% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         gte(15) ║       +70% ║    +188% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         gte(16) ║       +63% ║    +155% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          max(3) ║       +47% ║    +158% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          max(4) ║       +43% ║    +147% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          max(5) ║       +47% ║    +151% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          max(6) ║       +40% ║    +143% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          max(7) ║       +35% ║    +138% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          max(8) ║       +28% ║    +114% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          max(9) ║       +32% ║    +119% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         max(10) ║       +29% ║    +118% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         max(11) ║       +25% ║    +109% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         max(12) ║       +34% ║    +123% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         max(13) ║       +37% ║    +150% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         max(14) ║       +34% ║    +144% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         max(15) ║       +35% ║    +149% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         max(16) ║       +34% ║    +141% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          min(3) ║      +161% ║    +291% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          min(4) ║      +179% ║    +313% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          min(5) ║      +172% ║    +312% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          min(6) ║      +131% ║    +247% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          min(7) ║      +152% ║    +286% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          min(8) ║      +157% ║    +284% ║        0 ║  ║          0 ║       0 ║       0 ║  
║          min(9) ║      +129% ║    +255% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         min(10) ║      +140% ║    +272% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         min(11) ║      +153% ║    +276% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         min(12) ║      +132% ║    +261% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         min(13) ║      +138% ║    +261% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         min(14) ║      +130% ║    +248% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         min(15) ║      +132% ║    +241% ║        0 ║  ║          0 ║       0 ║       0 ║  
║         min(16) ║      +138% ║    +241% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    precision(3) ║          0 ║     +26% ║     +27% ║  ║          0 ║       0 ║       0 ║  
║    precision(4) ║          0 ║     +30% ║     +28% ║  ║          0 ║       0 ║       0 ║  
║    precision(5) ║          0 ║     +26% ║     +27% ║  ║          0 ║       0 ║       0 ║  
║    precision(6) ║          0 ║     +34% ║     +34% ║  ║          0 ║       0 ║       0 ║  
║    precision(7) ║          0 ║     +32% ║     +33% ║  ║          0 ║       0 ║       0 ║  
║    precision(8) ║          0 ║     +33% ║     +29% ║  ║          0 ║       0 ║       0 ║  
║    precision(9) ║          0 ║     +27% ║     +23% ║  ║          0 ║       0 ║       0 ║  
║   precision(10) ║          0 ║     +38% ║     +38% ║  ║          0 ║       0 ║       0 ║  
║   precision(11) ║          0 ║     +30% ║     +33% ║  ║          0 ║       0 ║       0 ║  
║   precision(12) ║          0 ║     +24% ║     +25% ║  ║          0 ║       0 ║       0 ║  
║   precision(13) ║          0 ║     +26% ║     +25% ║  ║          0 ║       0 ║       0 ║  
║   precision(14) ║          0 ║     +26% ║     +25% ║  ║          0 ║       0 ║       0 ║  
║   precision(15) ║          0 ║     +21% ║     +22% ║  ║          0 ║       0 ║       0 ║  
║   precision(16) ║          0 ║     +24% ║     +23% ║  ║          0 ║       0 ║       0 ║  
║     hashCode(3) ║       +77% ║     +97% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     hashCode(4) ║       +91% ║    +114% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     hashCode(5) ║       +87% ║     +68% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     hashCode(6) ║       +71% ║     +75% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     hashCode(7) ║       +77% ║     +93% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     hashCode(8) ║       +69% ║     +85% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     hashCode(9) ║       +92% ║     +64% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    hashCode(10) ║       +88% ║     +76% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    hashCode(11) ║       +90% ║    +112% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    hashCode(12) ║       +82% ║    +112% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    hashCode(13) ║       +89% ║    +107% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    hashCode(14) ║       +90% ║    +108% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    hashCode(15) ║       +96% ║    +114% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    hashCode(16) ║       +81% ║    +108% ║        0 ║  ║          0 ║       0 ║       0 ║  
║        scale(3) ║      +134% ║        0 ║        0 ║  ║          0 ║       0 ║       0 ║  
║        scale(4) ║      +129% ║      +2% ║        0 ║  ║          0 ║       0 ║       0 ║  
║        scale(5) ║      +154% ║      +4% ║        0 ║  ║          0 ║       0 ║       0 ║  
║        scale(6) ║      +134% ║      +4% ║        0 ║  ║          0 ║       0 ║       0 ║  
║        scale(7) ║      +131% ║        0 ║        0 ║  ║          0 ║       0 ║       0 ║  
║        scale(8) ║      +150% ║      +3% ║        0 ║  ║          0 ║       0 ║       0 ║  
║        scale(9) ║      +123% ║      +9% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       scale(10) ║      +144% ║     +13% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       scale(11) ║      +103% ║      +7% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       scale(12) ║      +146% ║      +8% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       scale(13) ║      +163% ║     +17% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       scale(14) ║      +130% ║      +8% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       scale(15) ║      +151% ║     +12% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       scale(16) ║      +150% ║     +10% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       signum(3) ║       +19% ║     +35% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       signum(4) ║       +19% ║     +37% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       signum(5) ║       +21% ║     +43% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       signum(6) ║       +17% ║     +34% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       signum(7) ║       +16% ║     +31% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       signum(8) ║       +19% ║     +32% ║        0 ║  ║          0 ║       0 ║       0 ║  
║       signum(9) ║       +14% ║     +28% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      signum(10) ║       +16% ║     +23% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      signum(11) ║       +22% ║     +45% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      signum(12) ║       +17% ║     +31% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      signum(13) ║       +20% ║     +37% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      signum(14) ║       +20% ║     +36% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      signum(15) ║       +20% ║     +37% ║        0 ║  ║          0 ║       0 ║       0 ║  
║      signum(16) ║       +16% ║     +28% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    byteValue(3) ║          0 ║    +128% ║     +87% ║  ║          0 ║    +81% ║       ∞ ║  
║    byteValue(4) ║          0 ║    +143% ║     +99% ║  ║          0 ║    +81% ║       ∞ ║  
║    byteValue(5) ║          0 ║    +108% ║     +88% ║  ║          0 ║    +81% ║       ∞ ║  
║    byteValue(6) ║          0 ║     +68% ║     +57% ║  ║          0 ║    +81% ║       ∞ ║  
║    byteValue(7) ║          0 ║     +44% ║     +34% ║  ║          0 ║    +54% ║       ∞ ║  
║    byteValue(8) ║       +17% ║      +5% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    byteValue(9) ║       +70% ║      +4% ║        0 ║  ║          0 ║       0 ║       0 ║  
║   byteValue(10) ║      +130% ║        0 ║        0 ║  ║          0 ║       0 ║       0 ║  
║   byteValue(11) ║      +243% ║        0 ║      +7% ║  ║          0 ║       0 ║       0 ║  
║   byteValue(12) ║      +418% ║        0 ║     +13% ║  ║          0 ║       0 ║       0 ║  
║   byteValue(13) ║      +790% ║        0 ║     +12% ║  ║          0 ║       0 ║       0 ║  
║   byteValue(14) ║     +1360% ║        0 ║     +10% ║  ║          0 ║       0 ║       0 ║  
║   byteValue(15) ║     +2634% ║        0 ║     +11% ║  ║          0 ║       0 ║       0 ║  
║   byteValue(16) ║     +5078% ║        0 ║     +12% ║  ║          0 ║       0 ║       0 ║  
║   shortValue(3) ║          0 ║    +132% ║     +91% ║  ║          0 ║    +81% ║       ∞ ║  
║   shortValue(4) ║          0 ║    +130% ║     +90% ║  ║          0 ║    +81% ║       ∞ ║  
║   shortValue(5) ║          0 ║     +99% ║     +82% ║  ║          0 ║    +90% ║       ∞ ║  
║   shortValue(6) ║          0 ║     +68% ║     +59% ║  ║          0 ║    +72% ║       ∞ ║  
║   shortValue(7) ║          0 ║     +47% ║     +40% ║  ║          0 ║    +81% ║       ∞ ║  
║   shortValue(8) ║       +13% ║      +4% ║        0 ║  ║          0 ║       0 ║       0 ║  
║   shortValue(9) ║       +55% ║      +1% ║        0 ║  ║          0 ║       0 ║       0 ║  
║  shortValue(10) ║      +118% ║        0 ║        0 ║  ║          0 ║       0 ║       0 ║  
║  shortValue(11) ║      +224% ║        0 ║      +6% ║  ║          0 ║       0 ║       0 ║  
║  shortValue(12) ║      +408% ║        0 ║     +13% ║  ║          0 ║       0 ║       0 ║  
║  shortValue(13) ║      +745% ║        0 ║     +10% ║  ║          0 ║       0 ║       0 ║  
║  shortValue(14) ║     +1302% ║        0 ║      +9% ║  ║          0 ║       0 ║       0 ║  
║  shortValue(15) ║     +2473% ║        0 ║      +9% ║  ║          0 ║       0 ║       0 ║  
║  shortValue(16) ║     +4433% ║        0 ║      +8% ║  ║          0 ║       0 ║       0 ║  
║     intValue(3) ║          0 ║    +159% ║    +111% ║  ║          0 ║    +81% ║       ∞ ║  
║     intValue(4) ║          0 ║    +168% ║    +125% ║  ║          0 ║    +81% ║       ∞ ║  
║     intValue(5) ║          0 ║    +122% ║     +98% ║  ║          0 ║    +81% ║       ∞ ║  
║     intValue(6) ║          0 ║     +60% ║     +49% ║  ║          0 ║    +72% ║       ∞ ║  
║     intValue(7) ║          0 ║     +39% ║     +32% ║  ║          0 ║    +63% ║       ∞ ║  
║     intValue(8) ║       +12% ║      +5% ║        0 ║  ║          0 ║       0 ║       0 ║  
║     intValue(9) ║       +57% ║      +4% ║        0 ║  ║          0 ║       0 ║       0 ║  
║    intValue(10) ║      +102% ║        0 ║        0 ║  ║          0 ║       0 ║       0 ║  
║    intValue(11) ║      +179% ║        0 ║      +5% ║  ║          0 ║       0 ║       0 ║  
║    intValue(12) ║      +332% ║        0 ║     +11% ║  ║          0 ║       0 ║       0 ║  
║    intValue(13) ║      +603% ║        0 ║      +8% ║  ║          0 ║       0 ║       0 ║  
║    intValue(14) ║     +1128% ║        0 ║      +8% ║  ║          0 ║       0 ║       0 ║  
║    intValue(15) ║     +2168% ║        0 ║      +8% ║  ║          0 ║       0 ║       0 ║  
║    intValue(16) ║     +3953% ║        0 ║      +7% ║  ║          0 ║       0 ║       0 ║  
║    longValue(3) ║          0 ║    +296% ║    +109% ║  ║          0 ║    +81% ║       ∞ ║  
║    longValue(4) ║          0 ║    +284% ║    +111% ║  ║          0 ║    +81% ║       ∞ ║  
║    longValue(5) ║          0 ║    +210% ║    +101% ║  ║          0 ║    +81% ║       ∞ ║  
║    longValue(6) ║          0 ║    +140% ║     +75% ║  ║          0 ║    +72% ║       ∞ ║  
║    longValue(7) ║          0 ║    +106% ║     +58% ║  ║          0 ║    +54% ║       ∞ ║  
║    longValue(8) ║          0 ║     +53% ║     +22% ║  ║          0 ║       0 ║       0 ║  
║    longValue(9) ║          0 ║     +24% ║        0 ║  ║          0 ║       0 ║       0 ║  
║   longValue(10) ║       +17% ║     +20% ║        0 ║  ║          0 ║       0 ║       0 ║  
║   longValue(11) ║       +52% ║      +7% ║        0 ║  ║          0 ║       0 ║       0 ║  
║   longValue(12) ║      +100% ║        0 ║      +1% ║  ║          0 ║       0 ║       0 ║  
║   longValue(13) ║      +234% ║        0 ║      +2% ║  ║          0 ║       0 ║       0 ║  
║   longValue(14) ║      +441% ║        0 ║      +4% ║  ║          0 ║       0 ║       0 ║  
║   longValue(15) ║      +872% ║        0 ║      +6% ║  ║          0 ║       0 ║       0 ║  
║   longValue(16) ║     +1568% ║        0 ║      +5% ║  ║          0 ║       0 ║       0 ║  
║   floatValue(3) ║          0 ║    +653% ║    +656% ║  ║          0 ║       0 ║       0 ║  
║   floatValue(4) ║          0 ║    +820% ║    +777% ║  ║          0 ║       0 ║       0 ║  
║   floatValue(5) ║          0 ║    +976% ║    +941% ║  ║          0 ║       0 ║       0 ║  
║   floatValue(6) ║          0 ║   +1149% ║   +1085% ║  ║          0 ║       0 ║       0 ║  
║   floatValue(7) ║          0 ║    +989% ║    +985% ║  ║          0 ║       0 ║       0 ║  
║   floatValue(8) ║          0 ║    +756% ║    +841% ║  ║          0 ║       0 ║       0 ║  
║   floatValue(9) ║          0 ║    +626% ║    +746% ║  ║          0 ║       0 ║       0 ║  
║  floatValue(10) ║          0 ║    +586% ║    +718% ║  ║          0 ║       0 ║       0 ║  
║  floatValue(11) ║          0 ║    +577% ║    +713% ║  ║          0 ║       0 ║       0 ║  
║  floatValue(12) ║          0 ║    +578% ║    +743% ║  ║          0 ║       0 ║       0 ║  
║  floatValue(13) ║          0 ║    +585% ║    +739% ║  ║          0 ║       0 ║       0 ║  
║  floatValue(14) ║          0 ║    +539% ║    +705% ║  ║          0 ║       0 ║       0 ║  
║  floatValue(15) ║          0 ║    +484% ║    +720% ║  ║          0 ║       0 ║       0 ║  
║  floatValue(16) ║          0 ║    +387% ║    +701% ║  ║          0 ║       0 ║       0 ║  
║  doubleValue(3) ║          0 ║     +31% ║     +24% ║  ║          0 ║       0 ║       0 ║  
║  doubleValue(4) ║          0 ║     +31% ║     +17% ║  ║          0 ║       0 ║       0 ║  
║  doubleValue(5) ║          0 ║     +25% ║     +18% ║  ║          0 ║       0 ║       0 ║  
║  doubleValue(6) ║          0 ║     +40% ║     +45% ║  ║          0 ║       0 ║       0 ║  
║  doubleValue(7) ║          0 ║     +41% ║     +58% ║  ║          0 ║       0 ║       0 ║  
║  doubleValue(8) ║          0 ║     +38% ║     +59% ║  ║          0 ║       0 ║       0 ║  
║  doubleValue(9) ║          0 ║     +34% ║     +54% ║  ║          0 ║       0 ║       0 ║  
║ doubleValue(10) ║          0 ║     +61% ║     +86% ║  ║          0 ║       0 ║       0 ║  
║ doubleValue(11) ║          0 ║    +124% ║    +151% ║  ║          0 ║       0 ║       0 ║  
║ doubleValue(12) ║          0 ║    +218% ║    +243% ║  ║          0 ║       0 ║       0 ║  
║ doubleValue(13) ║          0 ║    +339% ║    +340% ║  ║          0 ║       0 ║       0 ║  
║ doubleValue(14) ║          0 ║    +465% ║    +421% ║  ║          0 ║       0 ║       0 ║  
║ doubleValue(15) ║          0 ║    +583% ║    +494% ║  ║          0 ║       0 ║       0 ║  
║ doubleValue(16) ║          0 ║    +645% ║    +527% ║  ║          0 ║       0 ║       0 ║  
║     toBigInt(3) ║          0 ║     +65% ║     +34% ║  ║       +72% ║    +40% ║       0 ║  
║     toBigInt(4) ║          0 ║     +77% ║     +37% ║  ║       +72% ║    +40% ║       0 ║  
║     toBigInt(5) ║          0 ║     +75% ║     +36% ║  ║       +72% ║    +45% ║       0 ║  
║     toBigInt(6) ║          0 ║     +85% ║     +72% ║  ║       +60% ║    +40% ║       0 ║  
║     toBigInt(7) ║          0 ║    +104% ║     +98% ║  ║       +60% ║    +36% ║       0 ║  
║     toBigInt(8) ║          0 ║    +111% ║    +110% ║  ║       +50% ║    +27% ║       0 ║  
║     toBigInt(9) ║          0 ║    +101% ║    +110% ║  ║       +59% ║    +18% ║       0 ║  
║    toBigInt(10) ║          0 ║    +600% ║    +733% ║  ║          0 ║   +117% ║   +172% ║  
║    toBigInt(11) ║          0 ║    +923% ║   +1251% ║  ║          0 ║   +220% ║   +404% ║  
║    toBigInt(12) ║          0 ║   +1214% ║   +1710% ║  ║          0 ║   +253% ║   +480% ║  
║    toBigInt(13) ║          0 ║   +2079% ║   +2773% ║  ║          0 ║   +365% ║   +704% ║  
║    toBigInt(14) ║          0 ║   +4261% ║   +5128% ║  ║          0 ║  +1105% ║  +2166% ║  
║    toBigInt(15) ║          0 ║   +7637% ║   +8651% ║  ║          0 ║  +3441% ║  +6828% ║  
║    toBigInt(16) ║          0 ║   +9088% ║  +12775% ║  ║          0 ║  +7458% ║ +14835% ║  
╚═════════════════╩════════════╩══════════╩══════════╝  ╚════════════╩═════════╩═════════╝  

Long Encoding

The representation of a decimal value in Decimal encoding is achieved with the following model:

To represent a value such as 1234567.89, a Decimal-encoded long has two numbers inside it:

  1. value
    This is a variable range value (maximum of long) representing the full unscaled precision (all significant digits), i.e.:

    123456789
    
  2. scale
    This is a variable range value (maximum of short) representing the position of the decimal point in the unscaled value, i.e.:

    2
    

A decimal represented with Decimal encoding can be reconstituted with value and scale by multiplying the value by ten to the power of the negation of the scale (value ✕ 10⁻ˢᶜᵃˡᵉ), i.e.:

123456789 ✕ 10⁻² = 1234567.89

To maximize precision, the Decimal encoding implements a variable range for the scale. The variable range is defined by a scaleBits variable representing the number of bits inside the 64-bit long that are reserved for the signed representation of the scale. This effectively means that the variable range of value is 64 - bits.

Since both value and scale are signed, one bit is reserved for the sign in each. The following table provides sample value and scale ranges for various scale bits values:

For example, consider the following table with scale scaleBits as the variable:

scaleBits
[0, 16]
Scale range
[-2ᵇⁱᵗˢ⁻¹, 2ᵇⁱᵗˢ⁻¹ - 1]
valueBits
64-bits
Value range
[-2⁶³⁻ᵇⁱᵗˢ, 2⁶³⁻ᵇⁱᵗˢ - 1]
Example
 
0 [0, 0] 64 [-2⁶³, 2⁶³ - 1] Long.MAX_VALUE
1 [0, 0] 63 [-2⁶², 2⁶² - 1] 4611686018427387904
2 [-1, 0] 62 [-2⁶¹, 2⁶¹ - 1] 2305843009213693952E1
3 [-2, 1] 61 [-2⁶⁰, 2⁶⁰ - 1] 11529215046068469.76
4 [-8, 7] 60 [-2⁵⁹, 2⁵⁹ - 1] 57646075230.3423488
8 [-128, 127] 56 [-2⁵⁵, 2⁵⁵ - 1] 3.6028797018963968E111
16 [-32768, 32767] 48 [-2⁴⁷, 2⁴⁷ - 1] 1.40737488355328E−32768

Technically, scaleBits below 3 are not very useful. Therefore, Decimal officially supports scaleBits values between 3 and 16 with its unit tests. Some unit tests also test for scaleBits values of 0, 1 and 2, but this is supplementary.

The following illustrates the way Decimal encodes the value and scale inside a long primitive:

        scale sign bit (for scaleBits > 0)
       /
      1
.---+---+---- // --------+------------------------------ // -------------------------------.
|   |   '                |                                                                 |
|   |   '   scale        |                             value                               |
|   |   '                |                                                                 |
'---+---+---- // --------+----------------------------- // --------------------------------'
  0      [1, scaleBits+1]                  [scaleBits+1, 63-scaleBits]
   \
    value sign bit

Benchmark Results

  • All tests were run with Java 1.8.0_231 on Mac OS 10.15.6.
  • All tests were run with -Xcomp argument, for precompilation of JIT optimizations.

Benchmark tests are organized in 8 test classes, each responsible for its context of functions:

Link to results Link to test code
Addition and subtraction DecimalAdditionTest
Multiplication DecimalMultiplicationTest
Division DecimalDivisionTest
Predicate functions DecimalPredicateTest

FAQ

  1. Is Decimal error free?

    The development of Decimal utilized the same test framework as that of BigInt. The test framework is specifically designed to test the full breadth and adjustable depth of inputs into Decimal's algorithms. The test framework separates test inputs into "special" and "random". Special inputs are those that involve numbers representing special edges insofar as the number's long encoding, or the result of operations leading to propagating carrys of remainders. Random inputs are generated on a "breadth first" basis with respect to the input's decimal precision, allowing the depth (testing of more random values for a single precision) to be adjustable for the purposes of development vs comprehensive analysis.

  2. What is Decimal's biggest advantage?

    Decimal was created for one specific purpose: to lower the heap memory allocations for regular arithmetic operations. It achieves this with its single object allocation count in case of Decimal instances, or zero object allocation count in case of long-encoded numbers. In comparison, BigDecimal utilized BigInteger algorithms that liberally creates transient instances for the purpose of calculations, which results in a significant memory load and subsequent runtime performance load when the GC turns on. This situation is particularly relevant in applications that work with very many fixed-point numbers. An example of such an application is an Asset Trading Systems (Level 3) that consumes live streams of order data. Arbitrary precision arithmetic is necessary for Asset Trading Systems in lieu of the need for fixed point arithmetic.

  3. What is Decimal's biggest disadvantage?

    Though Decimal outperforms BigDecimal in many operations, there are a those in which it is lacking. One particular operation that is important to note is mul(T). Decimal utilizes BigInt's mul(T), which cannot match the performance of BigInteger's multiply(T) for "medium-sized numbers", because BigInteger's multiply(T) is implemented as an intrinsic function. BigInt comes close to this performance with its Critical Native implementation of its multiplication algorithms, but it is still not as fast. Nonetheless, where BigInt loses in isolated runtime performance, it gains back with its superior ability in reducing unnecessary heap memory allocation for transient calculations.

    Please refer to BigInt's Multiplication for benchmark statistics.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

This project is licensed under the MIT License - see the LICENSE.txt file for details.