LibJ Math is an extension to the java.math Java API. The classes in LibJ Math can be split in two categories:
- Higher-performance alternatives to functionalities present in
java.math. - Supplementary functionalities missing in
java.math.
An arbitrary-precision integer replacement for java.math.BigInteger, with the following differences:
- Mutable:
BigIntis mutable, allowing for reuse of allocated magnitude arrays. - Little-endian:
BigInt's magnitude array is in little-endian order, allowing for faster operations concerning changes to a number's scale. - Faster arithmetic: The arithmetic algorithms in
BigIntare implemented with the optimization of memory (heap allocation) and runtime performance in mind. - Faster multiplication of large numbers: Support parallel multiplication algorithm for large numbers.
- 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.
- Support for
intandlongparameters and return types:BigIntdoes not require its parameters or return types to beBigInt, avoiding unnecessary instantiation of transientBigIntobjects andint[]arrays. - Support for "object-less" operation: All methods in
BigIntare available in static form, allowing bareint[]value-encoded number arrays to be used without aBigIntinstance, leading to further reduction in heap memory allocation. - Significantly reduced heap allocation:
BigIntwas designed to reduce the number of instances allocated purely for the purpose of transient calculation, and significantly outperformsBigIntegerwith regard to memory and GC load. - No preemptive exception checking:
BigIntdoes 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. - Native bindings:
BigIntprovides select algorithms in 3 forms:
* Native Bindings are present in the built JAR for MacOS (x64 and M1), 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.
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 (
-1for negative, and1for 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.
BigInt is bundled with this module, which is available in the Maven Central Repository. The BigInt implementation provides JNI bindings for MacOS, Linux and Windows platforms (64-bit), 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:
- Linux: libcilkrts5
- MacOS: None
- Windows: None
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:
- 0: Represents the baseline.
- +###%: 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% ║
╚════════════════════╩════════════╩═════════╩═════════╝ ╚════════════╩══════════╩══════════╝
The BigInt implementation is accompanied by a custom test framework that provides:
-
Assert correctness of function results
The results of each test are asserted to be equal amongst all test subjects. -
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. -
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, andint[].
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:
- 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, orint[]) containing the0value (i.e. that test subject spends 0% less time than the baseline (itself) for the test).
- 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, orint[]) containing the0value (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:Tandint[]. Here,Trepresents the type of the test subject (BigInteger,BigInt, orint[]), andint[]represents theint[]type itself, as bothBigIntegerandBigIntuseint[]as the underlying representation of the number's magnitude. Therefore, for bareint[]value-encoded number arrays,Tandint[]refer to the same thing.
- 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 underlyingint[](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, orint[]) represent the mean time spent (nanoseconds) in the test method. If the test method being tested applies to one input (likeBigInteger.abs(), where the one input isthis), then the table will provide a single mean time spent value. If the test method being tested applies to two inputs (likeBigInteger.add(BigInteger), where the first input isthisand the second is some otherBigIntegerinstance), 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, orint[]) containing the0value (i.e. that test subject spends 0% less time than the baseline (itself) for the test).
- 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.
- 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 underlyingint[](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, orint[]) 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:Tandint[]. Here,Trepresents the type of the test subject (BigInteger,BigInt, orint[]), andint[]represents theint[]type itself, as bothBigIntegerandBigIntuseint[]as the underlying representation of the number's magnitude. Therefore, for bareint[]value-encoded number arrays,Tandint[]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, orint[]) containing the0value (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:Tandint[]. Here,Trepresents the type of the test subject (BigInteger,BigInt, orint[]), andint[]represents theint[]type itself, as bothBigIntegerandBigIntuseint[]as the underlying representation of the number's magnitude. Therefore, for bareint[]value-encoded number arrays,Tandint[]refer to the same thing.
- All tests were run with Java 1.8.0_231 on Mac OS 10.15.6.
- All tests were run with
-Xcompargument, for precompilation of JIT optimizations. - All tests were run with Critical Native bindings loaded, which automatically happens when
-Xcompis present on the JVM argument list.
Benchmark tests are organized in 8 test classes, each responsible for its context of functions:
-
Is
BigInterror free?With respect to the correctness of its algorithms,
BigInthas 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'sintencoding, 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
BigIntdoes 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. -
What is
BigInt's biggest advantage?BigIntwas created for one specific purpose: to lower the heap memory allocations for regular arithmetic operations.BigIntegerliberally 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. -
What is
BigInt's biggest disadvantage?Though
BigIntoutperformsBigIntegerin most operations, there are a few in which it is lacking. One particular operation that is important to note ismul(T)(i.e. multiplication of an arbitrary precision number by another arbitrary precision number).BigInt'smul(T)cannot match the performance ofBigInteger'smultiply(T)for "medium-sized numbers", becauseBigInteger'smultiply(T)is implemented as an intrinsic function.BigIntcomes close to this performance with its Critical Native implementation of its multiplication algorithms, but it is still not as fast. Nonetheless, whereBigIntloses 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.
-
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.
A 64-bit precision decimal alternative to java.math.BigDecimal, with the following differences:
- Avoids Heap Allocation: The
Decimalrepresents a fixed-point number inside alongprimitive, thus limiting the precision of aDecimal-encoded number to 64 bits, and eliminating the cost of heap allocation entirely. Please refer to Long Encoding for further details onDecimal's 64-bit Precision. - Support for "object-less" operation: All methods in
Decimalare available in static form, allowing applications to work solely withlong-encoded decimals. - Mutable:
Decimalobjects are mutable, allowing for reuse of allocated references. - 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 onDecimal's performance. - Significantly reduced heap allocation:
Decimalwas designed to reduce the number of instances allocated purely for the purpose of transient calculation, and significantly outperformsBigDecimalwith regard to memory and GC load. When utilizinglong-encoded decimals, memory and GC load is reduced to zero. - No preemptive exception checking:
Decimaldoes 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.
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:
- 0: Represents the baseline.
- +###%: 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 withBigDecimal. This effectively means that for each arithmetic operation,Decimalis also performing a reducedsetScale(scale)adjustment to ensure its number can fit in along-encoded number.- Operations on
long-encoded numbers are systematically slower than theirDecimalequivalents. This is due to the need for thevalueandscaleto be first decoded from along-encoded number prior to the arithmetic operation. Similarly, thevalueandscaleof the result of the operation need to be then re-encoded intolong-encoded number. Though these overhead operations are miniscule, they still do reduce the overall runtime perform of algorithms onlong-encoded decimals. - The use of the
∞symbol in Heap Allocation stats is due to zero heap allocation for algorithms onlong-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% ║
╚═════════════════╩════════════╩══════════╩══════════╝ ╚════════════╩═════════╩═════════╝
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:
value
This is a variable range value (maximum oflong) representing the full unscaled precision (all significant digits), i.e.:
123456789scale
This is a variable range value (maximum ofshort) representing the position of the decimal point in the unscaledvalue, 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] |
valueBits64-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
- All tests were run with Java 1.8.0_231 on Mac OS 10.15.6.
- All tests were run with
-Xcompargument, 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 |
-
Is
Decimalerror free?The development of
Decimalutilized the same test framework as that ofBigInt. The test framework is specifically designed to test the full breadth and adjustable depth of inputs intoDecimal'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'slongencoding, 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. -
What is
Decimal's biggest advantage?Decimalwas 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 ofDecimalinstances, or zero object allocation count in case oflong-encoded numbers. In comparison,BigDecimalutilizedBigIntegeralgorithms 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. -
What is
Decimal's biggest disadvantage?Though
DecimaloutperformsBigDecimalin many operations, there are a those in which it is lacking. One particular operation that is important to note ismul(T).DecimalutilizesBigInt'smul(T), which cannot match the performance ofBigInteger'smultiply(T)for "medium-sized numbers", becauseBigInteger'smultiply(T)is implemented as an intrinsic function.BigIntcomes close to this performance with its Critical Native implementation of its multiplication algorithms, but it is still not as fast. Nonetheless, whereBigIntloses 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.
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.
This project is licensed under the MIT License - see the LICENSE.txt file for details.




