如何处理 Java BigDecimal 性能?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/611732/
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
What to do with Java BigDecimal performance?
提问by Alexander Temerev
I write currency trading applications for living, so I have to work with monetary values (it's a shame that Java still doesn't have decimal float type and has nothing to support arbitrary-precision monetary calculations). "Use BigDecimal!" — you might say. I do. But now I have some code where performance isan issue, and BigDecimal is more than 1000 times (!) slower than double
primitives.
我为生活编写货币交易应用程序,所以我必须处理货币价值(遗憾的是,Java 仍然没有十进制浮点类型并且没有任何支持任意精度货币计算的东西)。“使用 BigDecimal!” ——你可能会说。我愿意。但现在我有一些代码在性能是一个问题,BigDecimal为超过1000次(!)慢于double
原语。
The calculations are very simple: what the system does is calculating a = (1/b) * c
many many times (where a
, b
and c
are fixed-point values). The problem, however, lies with this (1/b)
. I can't use fixed point arithmetic because there is no fixed point. And BigDecimal result = a.multiply(BigDecimal.ONE.divide(b).multiply(c)
is not only ugly, but sluggishly slow.
计算非常简单:系统所做的是a = (1/b) * c
多次计算(其中a
,b
和c
是定点值)。然而,问题就在于此(1/b)
。我不能使用定点算法,因为没有定点。而且BigDecimal result = a.multiply(BigDecimal.ONE.divide(b).multiply(c)
不仅丑陋,而且缓慢。
What can I use to replace BigDecimal? I need at least 10x performance increase. I found otherwise excellent JScience librarywhich has arbitrary-precision arithmetics, but it's even slower than BigDecimal.
我可以用什么来替换 BigDecimal?我需要至少 10 倍的性能提升。我发现其他优秀的JScience 库具有任意精度算术,但它甚至比 BigDecimal 还要慢。
Any suggestions?
有什么建议?
回答by Vladimir Dyuzhev
May be you should start with replacing a = (1/b) * c with a = c/b ? It's not 10x, but still something.
也许你应该开始用 a = c/b 替换 a = (1/b) * c ?它不是 10 倍,但仍然是一些东西。
If I were you, I'd create my own class Money, which would keep long dollars and long cents, and do math in it.
如果我是你,我会创建我自己的类 Money,它会保留多头美元和多头美分,并在其中进行数学运算。
回答by Pesto
Store longs as the number of cents. For example, BigDecimal money = new BigDecimal ("4.20")
becomes long money = 420
. You just have to remember to mod by 100 to get dollars and cents for output. If you need to track, say, tenths of a cent, it'd become long money = 4200
instead.
Store longs 为美分数。例如,BigDecimal money = new BigDecimal ("4.20")
变成long money = 420
。你只需要记住修改 100 以获得美元和美分的输出。如果你需要跟踪,比如说,十分之一美分,它就会变成long money = 4200
。
回答by sfossen
You might want to move to fixed point math. Just searching for some libraries right now. on sourceforge fixed-pointI haven't looked at this in depth yet. beartonics
您可能想要转向定点数学。现在只是在搜索一些图书馆。在 sourceforge定点上我还没有深入研究这个。健美操
Did you test with org.jscience.economics.money? since that has assured accuracy. The fixed point will only be as accurate as the # of bits assigned to each piece, but is fast.
你用 org.jscience.economics.money 测试过吗?因为这保证了准确性。固定点只会与分配给每个部分的位数一样准确,但速度很快。
回答by Tom Hawtin - tackline
1/b is not exactly representable with BigDecimal either. See the API docs to work out how the result is rounded.
1/b 也不能完全用 BigDecimal 表示。请参阅 API 文档以了解结果的舍入方式。
It shouldn't be toodifficult to write your own fixed decimal class based around a long field or two. I don't know any appropriate off the shelf libraries.
围绕一两个长字段编写自己的固定十进制类应该不会太难。我不知道任何合适的现成图书馆。
回答by DJClayworth
Assuming you can work to some arbitrary but known precision (say a billionth of a cent) and have a known maximum value you need handle (a trillion trillion dollars?) you can write a class which stores that value as an integer number of billionths of a cent. You'll need two longs to represent it. That should be maybe ten times as slow as using double; about a hundred times as fast as BigDecimal.
假设你可以工作到一些任意但已知的精度(比如十亿分之一美分)并且有一个你需要处理的已知最大值(一万亿万亿美元?),你可以编写一个类,将该值存储为十亿分之一的整数一分钱。你需要两个 long 来表示它。这应该比使用 double 慢十倍;大约是 BigDecimal 的一百倍。
Most of the operations are just performing the operation on each part and renormalizing. Division is slightly more complicated, but not much.
大多数操作只是对每个部分执行操作并重新规范化。除法稍微复杂一些,但并不多。
EDIT:In response to the comment. You will need to implement a bitshift operation on your class (easy as along as the multiplier for the high long is a power of two). To do division shift the divisor until it's not quite bigger than the dividend; subtract shifted divisor from dividend and increment the result (with appropriate shift). Repeat.
编辑:回应评论。你需要在你的类上实现一个位移操作(很简单,因为高长的乘数是二的幂)。做除法移动除数,直到它不比红利大;从被除数中减去移位的除数并增加结果(适当的移位)。重复。
EDIT AGAIN:You may find BigInteger does what you need here.
再次编辑:您可能会发现 BigInteger 在这里满足您的需求。
回答by TofuBeer
What version of the JDK/JRE are you using?
您使用的是什么版本的 JDK/JRE?
Also you might try ArciMath BigDecimalto see if theirs speeds it up for you.
您也可以尝试ArciMath BigDecimal看看他们的速度是否为您加速。
Edit:
编辑:
I remember reading somewhere (I think it was Effective Java) that the BigDecmal class was changed from being JNI called to a C library to all Java at some point... and it got faster from that. So it could be that any arbitrary precision library you use is not going to get you the speed you need.
我记得在某处读到过(我认为是 Effective Java),BigDecmal 类在某个时候从 JNI 调用变成了 C 库,变成了所有 Java ......而且它变得更快了。因此,您使用的任何任意精度库都可能无法获得所需的速度。
回答by basszero
Is JNI a possibility? You may be able to recover some speed and potentially leverage existing native fixed point libraries (maybe even some SSE* goodness too)
JNI有可能吗?您可能能够恢复一些速度并可能利用现有的本地定点库(甚至可能是一些 SSE* 优点)
Perhaps http://gmplib.org/
回答by SCdF
Personally, I don't think BigDecimal is ideal for this.
就个人而言,我认为 BigDecimal 不适合于此。
You really want to implement your own Money class using longs internally to represent the smallest unit (i.e. cent, 10th cent). There is some work in that, implementing add()
and divide()
etc, but it's not really that hard.
您真的想在内部使用 long 来实现您自己的 Money 类来表示最小单位(即美分、10 美分)。存在这样一些工作,实施add()
和divide()
等,但它并不真的那么难。
回答by Justin Standard
Can you provide more insight as to the purpose of the calculation?
您能否提供有关计算目的的更多见解?
What your dealing with is a trade-off between speed and precision. How great will the loss in precision be if you switched to a primitive?
您要处理的是速度和精度之间的权衡。如果切换到基元,精度损失会有多大?
I think in some cases the user may be comfortable with less accuracy in exchange for speed, so long as they can hone in on the accurate calculation when needed. It really depends on what you will use this calculation for.
我认为在某些情况下,用户可能会愿意以较低的准确性来换取速度,只要他们能够在需要时进行准确的计算。这实际上取决于您将使用此计算的目的。
Perhaps you can allow the user to preview the result quickly using doubles, and then request the more precise value using BigDecimal if they wish?
也许您可以允许用户使用双精度快速预览结果,然后根据需要使用 BigDecimal 请求更精确的值?
回答by John Nilsson
Maybe you should look into getting hardware accelerated decimal arithmetics?
也许您应该考虑获得硬件加速的十进制算法?