tools4j / decimal4j

Java library for fast fixed-point arithmetic based on longs with support for up to 18 decimal places.
decimal4j.org
MIT License
156 stars 17 forks source link

Multiplication for zero GC API #23

Closed cwengc closed 1 year ago

cwengc commented 1 year ago

Is there a good way to handle multiplication for numbers with the same scale in the most efficient manner possible?

terzerm commented 1 year ago

Hi, thanks for your question.

Is there a good way to handle multiplication for numbers with the same scale …

It depends a bit what you want exactly. If you multiply 2 numbers with scale d, the result has scale 2d in the general case. Is that what you want? By default decimal4j returns a result in the same scale as the first operand, that would be d here, and rounding or truncation may be required.

… in the most efficient manner possible?

Again depends a bit what you mean with this. Do you want a zero GC method, or just a convenient way to do it?

For an example for exact multiplication with result 2d scale check the multiplyExact() metods on the DenimslXf or MutableDecimalXf classes, where X is the scale. This however is not GC free.

For multiplication with result scale d and rounding or truncation, just use one of the multiply methods, here the MutableDecimal version will not allocate objects if you reuse it multiple times.

For Zero GC you need to get an arithmetic of the target scale, e.g. here 2 or 4 depending on the desired result scale. Consider this example for illustration:

//Example: 1.23 * 4.56 = 5.6088

//truncated or rounded result, arithmetic for scale 2
DecimalArithmetic roundUp = Scale2f.INSTANCE.getDefaultArithmetic();
DecimalArithmetic roundDown = Scale2f.INSTANCE.getRoundingDownArithmetic();
assertEquals(561, roundUp.multiply(123, 456));
assertEquals(560, roundDown.multiply(123, 456));

//exact result, we need target arithmetic of scale 4
DecimalArithmetic scale4 = Scale4f.INSTANCE.getRoundingDownArithmetic();//round down is fastest
long valA = scale4.fromUnscaled(123, 2);
long valB = scale4.fromUnscaled(456, 2);
assertEquals(56088, scale4.multiply(valA, valB));

Above answer and some other variants can also be viewed in the issue23() test method in FaqTest.java

More examples can be found in the wiki: