Skip to content

Instantly share code, notes, and snippets.

@hillmanli-seekers
Last active July 12, 2022 18:14
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save hillmanli-seekers/a8ab8e463e7b60989e6d0c0900cf4d93 to your computer and use it in GitHub Desktop.
Save hillmanli-seekers/a8ab8e463e7b60989e6d0c0900cf4d93 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;
}
}
@hillmanli-seekers
Copy link
Author

hillmanli-seekers commented Mar 30, 2017

A sample run will produce following result.

Time taken for double calculation: 1.716163ms
Time taken for Kahan double calculation: 3.549576ms
Time taken for BigDecimal calculation: 97.298124ms
Value diff for simple sum: 8.68145523891E-10
Value diff for Kahan sum: 1.854476109E-12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment