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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With