-
-
Save belgoros/b6f162d4aea1b9806784bd2670fbc377 to your computer and use it in GitHub Desktop.
BigDecimal vs double: illustration of accuracy and performance impact
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.math.BigDecimal; | |
import java.util.function.Consumer; | |
import java.util.function.DoubleSupplier; | |
import java.util.stream.DoubleStream; | |
public class TestDouble { | |
private static double doubleTotal = 0; | |
private static double kahanDoubleTotal = 0; | |
private static BigDecimal bdTotal = BigDecimal.ZERO; | |
public static void main(String[] args) { | |
int iteration = 100000; | |
double[] values = construct(Math::random, iteration); | |
System.out.printf("Time taken for double calculation: %fms%n", time(TestDouble::sumToDouble, values)); | |
System.out.printf("Time taken for Kahan double calculation: %fms%n", time(TestDouble::kahanSumToDouble, values)); | |
System.out.printf("Time taken for BigDecimal calculation: %fms%n", time(TestDouble::sumToBigDecimal, values)); | |
System.out.printf("Value diff for simple sum: %s%n", bdTotal.subtract(BigDecimal.valueOf(doubleTotal)).abs().toString()); | |
System.out.printf("Value diff for Kahan sum: %s%n", bdTotal.subtract(BigDecimal.valueOf(kahanDoubleTotal)).abs().toString()); | |
} | |
private static double time(Consumer<double[]> consumer, double[] values) { | |
long start = System.nanoTime(); | |
consumer.accept(values); | |
long end = System.nanoTime(); | |
return 1.0 * (end - start) / (1000 * 1000); | |
} | |
private static double[] construct(DoubleSupplier supplier, int size) { | |
return DoubleStream | |
.iterate(supplier.getAsDouble(), operand -> supplier.getAsDouble()) | |
.limit(size) | |
.toArray(); | |
} | |
private static void kahanSumToDouble(double[] values) { | |
double approxError = 0; | |
for (double value : values) { | |
double adjustedValue = value - approxError; | |
double adjustedSum = kahanDoubleTotal + adjustedValue; | |
approxError = (adjustedSum - kahanDoubleTotal) - adjustedValue; | |
kahanDoubleTotal = adjustedSum; | |
} | |
} | |
private static void sumToDouble(double[] values) { | |
for (double value : values) { | |
doubleTotal += value; | |
} | |
} | |
private static void sumToBigDecimal(double[] values) { | |
BigDecimal ret = BigDecimal.ZERO; | |
for (double value : values) { | |
ret = ret.add(BigDecimal.valueOf(value)); | |
} | |
bdTotal = ret; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment