java java中具有快速性能的定点算法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11916308/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 06:55:36  来源:igfitidea点击:

fixed point arithmetics in java with fast performance

javafixed-point

提问by Karel Bílek

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.)

我需要在Java中以完美的精度和固定的小数点后小数点数来表示一些数字;在那个小数点之后,我不在乎。(更具体地说 - 金钱和百分比。)

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

我现在使用 Java 自己的 BigDecimal,但我发现它真的很慢,并且开始显示在我的应用程序中。

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?

现在,我很可能可以自己编写它(我可能会),但真的,我真的是第一个需要它的人吗?不是已经有一些图书馆了吗?

采纳答案by Thomas Mueller

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

您是否完全确定 BigDecimal 是性能问题?你用分析器找出来了吗?如果是,有两个可能有帮助的选项是:

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

1) 使用long所有值并将其乘以一个因子(例如,如果您对美分感兴趣,则为 100)。

2) Use a specially designed class that implements something similar to BigDecimal, but using longinternally. 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 BigDecimaluses a longinternally as well except if high precision is needed, so this solution will only help a tiny bit in most cases.

2) 使用一个专门设计的类,它实现了类似于 的东西BigDecimal,但在long内部使用。我不知道是否存在一个好的开源库(也许是Java Math Fixed Point Library?)。我很久以前(我相信是 2001 年)为 J2ME 自己写了一个这样的类。做对有点棘手。请注意,除非需要高精度,否则内部也BigDecimal使用 a long,因此该解决方案在大多数情况下只会有一点帮助。

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

double由于舍入和精度问题,在许多情况下使用并不是一个好的选择。

回答by marco

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

decimal4j是一个 Java 库,用于基于 longs 的快速固定精度算术,最多支持 18 位小数。

Disclaimer:I am involved in the decimal4j project.

免责声明:我参与了 decimal4j 项目。

回答by Ondra ?i?ka

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

虽然这不是您所要问的,但这可以在不离开的情况下加速您的应用程序BigDecimal

Since Java 8, this is solved by BigDecimalitself. A new class MathContextwas added and limits the precision to which the operations are calculated.

从 Java 8 开始,这可以BigDecimal自行解决。添加了一个新类MathContext并限制了计算操作的精度。

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

The catch is that the precision 10does 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).

问题是精度10不适用于小数点后的数字。它适用于有效位数。对于1234.50,需要 6。
对于1_500_000_000.100,需要 13 来保持数字不变。
因此,当您拥有 10 的精度并计算数十亿捷克克朗时,精度可能会受到影响。
尽管如此,例如 1000 的精度比无限精度(我认为这是默认值)要快得多。

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));

回答by Peter Lawrey

Not sure why you need a library for it.

不知道为什么你需要一个图书馆。

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

例如,假设您要添加两个具有相同固定精度的 long

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.

假设您要打印一个带有 3 个小数位的固定精度数字。

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

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

也许您过度思考这个问题并假设您需要一个库来处理所有事情。

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

如果您正在使用long或者double您可能需要少量辅助方法进行舍入,但您不需要这样的库。