fixed point arithmetics in java with fast performance

做~自己de王妃 提交于 2019-11-27 22:31:51

问题


I need to represent some numbers in Java with perfect precision and fixed number of decimal points after decimal point; after that decimal point, I don't care. (More concretely - money and percentages.)

I used Java's own BigDecimal now, but I found out, that it's really slow and it starts to show in my application.

So I want to solve it with a "regular" integers and a fixed-point arithmetics (long integers have big enough precision for my purposes).

Now, I would think that I am not the first one who has this kind of problem and there would be already a library for that, that already has multiplication/division implemented - but it seems that it isn't.

Now, I very probably can write it myself (and I probably will), but really, am I really the first person that needs this? Isn't there already some library for that?


回答1:


Are you completely sure BigDecimal is the performance problem? Did you use a profiler to find out? If yes, two options that could help are:

1) Use long and multiply all values by a factor (for example 100 if you are interested in cents).

2) Use a specially designed class that implements something similar to BigDecimal, but using long internally. I don't know if a good open source library exists (maybe the Java Math Fixed Point Library?). I wrote one such class myself quite a long time ago (2001 I believe) for J2ME. It's a bit tricky to get right. Please note BigDecimal uses a long internally as well except if high precision is needed, so this solution will only help a tiny bit in most cases.

Using double isn't a good option in many cases, because of rounding and precision problems.




回答2:


decimal4j is a Java library for fast fixed precision arithmetic based on longs with support for up to 18 decimal places.

Disclaimer: I am involved in the decimal4j project.




回答3:


Although this is not exactly what you are asking about, this can speed up your app without leaving BigDecimal:

Since Java 8, this is solved by BigDecimal itself. A new class MathContext was added and limits the precision to which the operations are calculated.

var num = new BigDecimal("1234.56780", new MathContext(10, RoundingMode.DOWN));

The catch is that the precision 10 does not apply to digits after decimal point. It applies to the number of significant digits. For 1234.50, 6 is needed.
For 1_500_000_000.100, 13 is needed to keep the number as is.
So the precision might suffer when you had a precision of 10 and counted billions of Czech Korunas.
Still, a precision of, say, 1000, is way faster than unlimited precision (which is I think the default).

This can also be applied to the individual operations:

BigDecimal n = new BigDecimal("0.12345");
n = n.pow(2, new MathContext(1000, RoundingMode.DOWN));
n = n.pow(2, new MathContext(1000, RoundingMode.DOWN));
n = n.pow(2, new MathContext(1000, RoundingMode.DOWN));
n = n.pow(2, new MathContext(1000, RoundingMode.DOWN));



回答4:


Not sure why you need a library for it.

For example, say you want to add two longs with the same fixed precision

long c = a + b;

Say you have a fixed precision number you want to multiple by an integer

long c = a * i;

Say you want to divide a number by a integer rounding to zero

long c = a / i;

Say you want to print a fixed precision number with 3 decimal places.

System.out.println(c / 1e3);

Perhaps you are over thinking the problem and assuming you need a library for everything.

If you are using long or double you might want a small number helper methods for rounding, but you don't need a library as such.



来源:https://stackoverflow.com/questions/11916308/fixed-point-arithmetics-in-java-with-fast-performance

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!