Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is adding up parsed doubles slower than using BigDecimal in Java?

Why is

  • result += Double.parseDouble(numberAsString)

with result being a double primitive, slower than

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

with result being a BigDecimal?

Benchmarks:

@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;
}

Since primitives usually have the reputation of computing faster than non-primitives the results are astonishing (at least to me):

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

That's 1024.567 ops/s for addition of BigDecimals but only 484.070 ops/s for addition using a primitive (benchmarked in JMH).

Why is this so? If there is a way to optimise addition of double primitives parsed from Strings beyond the speed of BigDecimal, please include this in your answer.

like image 686
ig-dev Avatar asked Jul 10 '26 17:07

ig-dev


1 Answers

You are really doing 2 things. PARSING and ADDING, yet you are accusing the primitive addition of being slower[if you really dissect your initial question, and your comment, "Since primitives usually have the reputation of COMPUTING faster than non-primitives the results are astonishing (at least to me):"].

Perhaps the addition operation isn't the slow operation for the double. Perhaps the parsing on primitives is what is slower, while the addition of the primitives is faster. I would try many more benchmarks, like the following

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

Also consider the possibility that shorter numbers might parse quickly for BigDecimal while longer numbers may not. I would try the benchmark using different number ranges

like image 151
Zachary Thomas Avatar answered Jul 12 '26 07:07

Zachary Thomas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!