为什么在Java中使用BigDecimal比将解析后的双精度加倍?

时间:2018-06-07 05:36:56

标签: java performance performance-testing

为什么

  • result += Double.parseDouble(numberAsString)

resultdouble原语,慢于

  • result = result.add(new BigDecimal(numberAsStrings))

resultBigDecimal

基准:

@Setup
public void beforeEach() {
    numbersAsStrings = new String[NUMBER_COUNT];
    double currentNumber = 1;
    for (int i = 0; i < NUMBER_COUNT; i++) {
        numbersAsStrings[i] = String.valueOf(currentNumber);
        currentNumber += 0.1;
    }
}

@Benchmark
public double addUpDoublesParsedFromString() {
    double result = 0;
    for (int i = 0; i < numbersAsStrings.length; i++) {
        result += Double.parseDouble(numbersAsStrings[i]);
    }
    return result;
}

@Benchmark
public BigDecimal addUpBigDecimalsFromString() {
    BigDecimal result = new BigDecimal(0);
    for (int i = 0; i < numbersAsStrings.length; i++) {
         result = result.add(new BigDecimal(numbersAsStrings[i]));
    }
    return result;
}

由于原语通常比非原语具有更快的计算声誉,因此结果令人惊讶(至少对我而言):

Benchmark                                                   Mode  Samples      Score  Score error  Units

t.n.b.n.BigDecimalVsDouble.addUpDoublesParsedFromString    thrpt        4    484.070       59.905  ops/s
t.n.b.n.BigDecimalVsDouble.addUpBigDecimalsFromString      thrpt        4   1024.567      170.329  ops/s

用于添加BigDecimals的1024.567 ops / s,但使用原语(在JMH中进行基准测试)仅添加484.070 ops / s。

为什么会这样?如果有一种方法可以优化从字符串中解析的double原语的添加超出BigDecimal的速度,请在答案中包含此内容。

1 个答案:

答案 0 :(得分:1)

你真的在做两件事。 PARSING和ADDING,但你指责原始的加法更慢[如果你真的剖析了你的初始问题和你的评论,“因为原语通常比非原语更快地得到COMPUTING的声誉,结果令人惊讶(至少对我而言) ):“]。

也许添加操作不是double的慢速操作。也许对原语进行解析的速度较慢,而原语的添加速度更快。我会尝试更多基准测试,如下面的

double[] doubleValues;
BigDecimal[] bdValues;

@Setup
public void beforeEach() {
    numbersAsStrings = new String[NUMBER_COUNT];
    doubleValues = new double[NUMBER_COUNT];
    bdValues = new BigDecimal[NUMBER_COUNT]; 
    double currentNumber = 1;
    for (int i = 0; i < NUMBER_COUNT; i++) {
        numbersAsStrings[i] = String.valueOf(currentNumber);
        doubleValues[i] = Double.parseDouble(numbersAsStrings[i]);
        bdValues[i] = new BigDecimal(numbersAsStrings[i]);
        currentNumber += 0.1;
    }
}




//additional benchmarks

@Benchmark
public double addUpDoubles() {
    double result = 0;
    for (int i = 0; i < numbersAsStrings.length; i++) {
        result += doubleValues[i];
    }
    return result;
}

@Benchmark
public BigDecimal addUpBigDecimals() {
    BigDecimal result = new BigDecimal(0);
    for (int i = 0; i < numbersAsStrings.length; i++) {
         result = result.add(bdValues[i]);
    }
    return result;
}

@Benchmark
public void doublesParsedFromString() {
    for (int i = 0; i < numbersAsStrings.length; i++) {
        Double d = Double.parseDouble(numbersAsStrings[i]);
    }
}

@Benchmark
public void bigDecimalsParsedFromString() {
    for (int i = 0; i < numbersAsStrings.length; i++) {
         BigDecimal bd = new BigDecimal(numbersAsStrings[i]);
    }
}



//original benchmarks-----------------------

@Benchmark
public double addUpDoublesParsedFromString() {
    double result = 0;
    for (int i = 0; i < numbersAsStrings.length; i++) {
        result += Double.parseDouble(numbersAsStrings[i]);
    }
    return result;
}

@Benchmark
public BigDecimal addUpBigDecimalsFromString() {
    BigDecimal result = new BigDecimal(0);
    for (int i = 0; i < numbersAsStrings.length; i++) {
         result = result.add(new BigDecimal(numbersAsStrings[i]));
    }
    return result;
}

还要考虑较短的数字可能会快速解析BigDecimal,而较长的数字可能不会。我会尝试使用不同数字范围的基准