Так что мой первоначальный ответ был просто неправильным, потому что мой тест был написан плохо. Я думаю, что я тот, кого следовало бы подвергнуть критике, а не ОП;) Возможно, это был один из первых тестов, которые я когда-либо писал ... ну, вот как вы учитесь. Вместо того, чтобы удалить ответ, вот результаты, где я не измеряю неправильную вещь. Некоторые заметки:
- Пересчитайте массивы, чтобы я не связывался с результатами, генерируя их
- Не никогда звоните
BigDecimal.doubleValue()
, так как это очень медленно
- Не связывайтесь с результатами, добавив
BigDecimal
s. Просто верните одно значение и используйте оператор if, чтобы предотвратить оптимизацию компилятора. Удостоверьтесь, что он работает большую часть времени, чтобы предсказание ветвлений могло исключить эту часть кода.
Тесты:
- BigDecimal: делайте математику в точности так, как вы ее предложили
- BigDecNoRecip: (1 / b) * c = c / b, просто сделайте c / b
- Двойной: сделать математику с двойными
Вот вывод:
0% Scenario{vm=java, trial=0, benchmark=Double} 0.34 ns; ?=0.00 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=BigDecimal} 356.03 ns; ?=11.51 ns @ 10 trials
67% Scenario{vm=java, trial=0, benchmark=BigDecNoRecip} 301.91 ns; ?=14.86 ns @ 10 trials
benchmark ns linear runtime
Double 0.335 =
BigDecimal 356.031 ==============================
BigDecNoRecip 301.909 =========================
vm: java
trial: 0
Вот код:
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.Random;
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
public class BigDecimalTest {
public static class Benchmark1 extends SimpleBenchmark {
private static int ARRAY_SIZE = 131072;
private Random r;
private BigDecimal[][] bigValues = new BigDecimal[3][];
private double[][] doubleValues = new double[3][];
@Override
protected void setUp() throws Exception {
super.setUp();
r = new Random();
for(int i = 0; i < 3; i++) {
bigValues[i] = new BigDecimal[ARRAY_SIZE];
doubleValues[i] = new double[ARRAY_SIZE];
for(int j = 0; j < ARRAY_SIZE; j++) {
doubleValues[i][j] = r.nextDouble() * 1000000;
bigValues[i][j] = BigDecimal.valueOf(doubleValues[i][j]);
}
}
}
public double timeDouble(int reps) {
double returnValue = 0;
for (int i = 0; i < reps; i++) {
double a = doubleValues[0][reps & 131071];
double b = doubleValues[1][reps & 131071];
double c = doubleValues[2][reps & 131071];
double division = a * (1/b) * c;
if((i & 255) == 0) returnValue = division;
}
return returnValue;
}
public BigDecimal timeBigDecimal(int reps) {
BigDecimal returnValue = BigDecimal.ZERO;
for (int i = 0; i < reps; i++) {
BigDecimal a = bigValues[0][reps & 131071];
BigDecimal b = bigValues[1][reps & 131071];
BigDecimal c = bigValues[2][reps & 131071];
BigDecimal division = a.multiply(BigDecimal.ONE.divide(b, MathContext.DECIMAL64).multiply(c));
if((i & 255) == 0) returnValue = division;
}
return returnValue;
}
public BigDecimal timeBigDecNoRecip(int reps) {
BigDecimal returnValue = BigDecimal.ZERO;
for (int i = 0; i < reps; i++) {
BigDecimal a = bigValues[0][reps & 131071];
BigDecimal b = bigValues[1][reps & 131071];
BigDecimal c = bigValues[2][reps & 131071];
BigDecimal division = a.multiply(c.divide(b, MathContext.DECIMAL64));
if((i & 255) == 0) returnValue = division;
}
return returnValue;
}
}
public static void main(String... args) {
Runner.main(Benchmark1.class, new String[0]);
}
}