Почему сложение анализируемых удваивается медленнее, чем использование BigDecimal в Java? - PullRequest
0 голосов
/ 07 июня 2018

Почему

  • result += Double.parseDouble(numberAsString)

с result примитивом double, медленнее

  • result = result.add(new BigDecimal(numberAsStrings))

с result, являющимся BigDecimal?

Тесты:

@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;
}

Поскольку примитивы обычно имеют репутацию вычислений быстрее, чем не примитивырезультаты поразительны (по крайней мере для меня):

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

Это 1024,567 операций / с для добавления BigDecimals, но только 484,070 операций / с для добавления с использованием примитива (тестируется в JMH).

Почему это так?Если есть способ оптимизировать добавление double примитивов, анализируемых из строк, со скоростью, превышающей BigDecimal, укажите это в своем ответе.

1 Ответ

0 голосов
/ 13 июня 2018

Вы действительно делаете 2 вещи.Парсинг и добавление, но вы обвиняете примитивное добавление в том, что он медленнее [если вы действительно разбираете свой первоначальный вопрос и ваш комментарий: «Поскольку примитивы обычно имеют репутацию ВЫЧИСЛЕНИЯ быстрее, чем не примитивы, результаты поразительны (по крайней мере для меня)): "].

Возможно, операция сложения не является медленной операцией для двойника.Возможно, разбор примитивов происходит медленнее, тогда как добавление примитивов происходит быстрее.Я бы попробовал еще много тестов, как, например,

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;
}

Также рассмотрите возможность быстрого разбора более коротких чисел для BigDecimal, а более длинных - нет.Я бы попробовал бенчмарк, используя разные диапазоны чисел

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...