Skip to content

Instantly share code, notes, and snippets.

@belgoros
Forked from hillmanli-seekers/TestDouble.java
Created June 4, 2021 14:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save belgoros/b6f162d4aea1b9806784bd2670fbc377 to your computer and use it in GitHub Desktop.
Save belgoros/b6f162d4aea1b9806784bd2670fbc377 to your computer and use it in GitHub Desktop.
BigDecimal vs double: illustration of accuracy and performance impact
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