首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何处理Java BigDecimal性能?

如何处理Java BigDecimal性能?
EN

Stack Overflow用户
提问于 2009-03-05 01:58:35
回答 21查看 40.5K关注 0票数 61

我编写货币交易应用程序是为了谋生,所以我必须处理货币值(遗憾的是,Java仍然没有decimal float类型,也没有支持任意精度的货币计算)。“使用BigDecimal!”--你可能会说。我知道。但现在我有一些代码,其中性能的一个问题,而BigDecimal超过1000倍(!)比double原语慢。

计算非常简单:系统所做的是多次计算a = (1/b) * c (其中abc是定点数值)。然而,问题出在这个(1/b)上。我不能用定点算术,因为没有不动点。而且BigDecimal result = a.multiply(BigDecimal.ONE.divide(b).multiply(c)不仅丑陋,而且运行缓慢。

我可以用什么来替代BigDecimal?我需要至少10倍的性能提升。我发现其他方面都很好的JScience library,它有任意精度的算术,但它甚至比BigDecimal还慢。

有什么建议吗?

EN

回答 21

Stack Overflow用户

发布于 2009-03-04 18:02:07

也许您应该从a= (1/b) *c替换为a= c/b开始?虽然不是10倍,但仍然很不错。

如果我是你,我会创造我自己的班级资金,它将保留长期美元和长期美分,并在其中进行数学计算。

票数 39
EN

Stack Overflow用户

发布于 2009-03-04 19:26:33

大多数double操作都会给你足够的精确度。你可以用两倍的精度代表10万亿美元,这对你来说可能已经足够了。

在我工作过的所有交易系统中(四家不同的银行),他们都使用了双精度,并进行了适当的舍入。我看不出有任何理由要使用BigDecimal。

票数 18
EN

Stack Overflow用户

发布于 2013-02-07 00:23:26

所以我最初的回答是完全错误的,因为我的基准测试写得很糟糕。我想我才是那个应该被批评的人,而不是OP ;)这可能是我写的第一个基准测试之一……哦,好吧,这就是你学习的方式。这里的结果不是删除答案,而是我没有测量错误的东西。一些注意事项:

  • 预先计算数组,这样我就不会通过生成它们来扰乱结果
  • 永远不要调用BigDecimal.doubleValue(),因为它非常慢
  • 不要通过添加BigDecimals来扰乱结果,只返回一个值,并使用if语句来阻止编译器优化。不过,请确保它在大部分时间内都能正常工作,以允许分支预测消除该部分代码。

测试:

Double

  • BigDecimal:完全按照您的建议计算it

  • BigDecNoRecip:(1/b) *c= c/b,只需执行c/b

  • :使用Double

执行数学运算

下面是输出:

代码语言:javascript
复制
 0% Scenario{vm=java, trial=0, benchmark=Double} 0.34 ns; ?=0.00 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=BigDecimal} 356.03 ns; ?=11.51 ns @ 10 trials
67% Scenario{vm=java, trial=0, benchmark=BigDecNoRecip} 301.91 ns; ?=14.86 ns @ 10 trials

    benchmark      ns linear runtime
       Double   0.335 =
   BigDecimal 356.031 ==============================
BigDecNoRecip 301.909 =========================

vm: java
trial: 0

代码如下:

代码语言:javascript
复制
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.Random;

import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;

public class BigDecimalTest {
  public static class Benchmark1 extends SimpleBenchmark {
    private static int ARRAY_SIZE = 131072;

    private Random r;

    private BigDecimal[][] bigValues = new BigDecimal[3][];
    private double[][] doubleValues = new double[3][];

    @Override
    protected void setUp() throws Exception {
      super.setUp();
      r = new Random();

      for(int i = 0; i < 3; i++) {
        bigValues[i] = new BigDecimal[ARRAY_SIZE];
        doubleValues[i] = new double[ARRAY_SIZE];

        for(int j = 0; j < ARRAY_SIZE; j++) {
          doubleValues[i][j] = r.nextDouble() * 1000000;
          bigValues[i][j] = BigDecimal.valueOf(doubleValues[i][j]); 
        }
      }
    }

    public double timeDouble(int reps) {
      double returnValue = 0;
      for (int i = 0; i < reps; i++) {
        double a = doubleValues[0][reps & 131071];
        double b = doubleValues[1][reps & 131071];
        double c = doubleValues[2][reps & 131071];
        double division = a * (1/b) * c; 
        if((i & 255) == 0) returnValue = division;
      }
      return returnValue;
    }

    public BigDecimal timeBigDecimal(int reps) {
      BigDecimal returnValue = BigDecimal.ZERO;
      for (int i = 0; i < reps; i++) {
        BigDecimal a = bigValues[0][reps & 131071];
        BigDecimal b = bigValues[1][reps & 131071];
        BigDecimal c = bigValues[2][reps & 131071];
        BigDecimal division = a.multiply(BigDecimal.ONE.divide(b, MathContext.DECIMAL64).multiply(c));
        if((i & 255) == 0) returnValue = division;
      }
      return returnValue;
    }

    public BigDecimal timeBigDecNoRecip(int reps) {
      BigDecimal returnValue = BigDecimal.ZERO;
      for (int i = 0; i < reps; i++) {
        BigDecimal a = bigValues[0][reps & 131071];
        BigDecimal b = bigValues[1][reps & 131071];
        BigDecimal c = bigValues[2][reps & 131071];
        BigDecimal division = a.multiply(c.divide(b, MathContext.DECIMAL64));
        if((i & 255) == 0) returnValue = division;
      }
      return returnValue;
    }
  }

  public static void main(String... args) {
    Runner.main(Benchmark1.class, new String[0]);
  }
}
票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/611732

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档