首页 > 解决方案 > 为什么加起来解析的双精度数比在 Java 中使用 BigDecimal 慢?

问题描述

为什么是

result作为一个原始人,double

result作为一个BigDecimal

基准:

@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,请在您的答案中包含此内容。

标签: javaperformanceperformance-testing

解决方案


你真的在做两件事。解析和添加,但是您指责原始添加速度较慢[如果您真的剖析了最初的问题和您的评论,“由于原语通常比非原语具有计算速度更快的声誉,因此结果令人惊讶(至少对我而言) ):"]。

也许加法运算不是双倍的慢速运算。也许对原语的解析速度较慢,而添加原语则更快。我会尝试更多的基准测试,如下所示

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 快速解析,而较长的数字可能不会。我会尝试使用不同的数字范围进行基准测试


推荐阅读