Java двойная скорость вычислений - PullRequest
1 голос
/ 29 января 2012

У меня есть фрагмент кода, который должен выполнить много вычислений, основанных на двойных значениях, что занимает слишком много времени. Могу ли я ускорить это, опустив несколько знаков после запятой? если я использую средство форматирования для парсинга двойного числа, разве это не сделает сначала исчисление, а затем сбросит лишние десятичные дроби, чтобы ничего не было получено? Каков наилучший способ сделать это?

Просто кое-что, чтобы понять:

double avgRatingForPreferredItem = (double) tempAverageRating.get(matrix.get(0).getItemID1())/matrix.size(); 
   double avgRatingForRandomItem = (double) tempAverageRating.get(matrix.get(0).getItemID2())/matrix.size();

double numarator = 0;
   for (MatrixColumn matrixCol : matrix) {
     numarator += ( matrixCol.getRatingForItemID1() - avgRatingForPreferredItem ) * (matrixCol.getRatingForItemID2() - avgRatingForRandomItem);
   }

   double numitor = 0;
   double numitorStanga = 0;
   double numitorDreapta = 0;
   for (MatrixColumn matrixCol : matrix) {
     numitorStanga += (matrixCol.getRatingForItemID1() - avgRatingForPreferredItem) * (matrixCol.getRatingForItemID1() - avgRatingForPreferredItem);
     numitorDreapta += (matrixCol.getRatingForItemID2() - avgRatingForRandomItem) * (matrixCol.getRatingForItemID2() - avgRatingForRandomItem);
   }

   numitor = Math.sqrt( numitorStanga * numitorDreapta );

   double corelare = numarator/numitor;

Ответы [ 4 ]

3 голосов
/ 29 января 2012

Я не верю, что фактические значения могут иметь какое-либо значение.

Стоит хотя бы попытаться сократить вычисления здесь:

for (MatrixColumn matrixCol : matrix) {
 numitorStanga  += (matrixCol.getRatingForItemID1() - avgRatingForPreferredItem)
                 * (matrixCol.getRatingForItemID1() - avgRatingForPreferredItem);
 numitorDreapta += (matrixCol.getRatingForItemID2() - avgRatingForRandomItem) 
                 * (matrixCol.getRatingForItemID2() - avgRatingForRandomItem);
}

Это зависит от того, насколько умным является JIT-компилятор - и я предполагаю, что getRatingforItemID1 и getRatingforItemID2 являются просто сквозными свойствами - но ваш код по крайней мере выглядит , как будто он выполняет избыточные вычитания. Итак:

for (MatrixColumn matrixCol : matrix) {
  double diff1 = matrixCol.getRatingForItemID1() - avgRatingForPreferredItem;
  double diff2 = matrixCol.getRatingForItemID2() - avgRatingForPreferredItem;
  numitorStanga += diff1 * diff1;
  numitorDreapta += diff2 * diff2;
}

Вы можете попробовать , изменив все на float вместо double - на некоторых архитектурах, которые могут сделать вещи быстрее; на других это может и не быть.

Вы абсолютно уверены, что код, который вы показали, имеет проблему? Это всего лишь алгоритм O (N) - сколько времени это занимает, и насколько велика матрица?

2 голосов
/ 29 января 2012

Вычисления с плавающей точкой имеют одинаковую скорость независимо от десятичных разрядов.Это аппаратное обеспечение , поэтому в любом случае оно работает с полным значением.Также имейте в виду, что число десятичных мест в любом случае не имеет значения, double хранит числа в двоичном , и просто усечение десятичных знаков вполне может создать двоичное представление одинаковой длины.*

1 голос
/ 29 января 2012

Другой способ сделать это быстрее - использовать массивы вместо объектов. Проблема с использованием объектов в том, что вы не представляете, как они расположены в памяти (часто, по моему опыту, это плохо, поскольку JVM вообще не оптимизируется для этого)

double avgRatingForPreferredItem = (double) tempAverageRating.get(matrix.get(0).getItemID1()) / matrix.size();
double avgRatingForRandomItem = (double) tempAverageRating.get(matrix.get(0).getItemID2()) / matrix.size();

double[] ratingForItemID1 = matrix.getRatingForItemID1();
double[] ratingForItemID2 = matrix.getRatingForItemID2();
double numarator = 0, numitorStanga = 0, numitorDreapta = 0;
for (int i = 0; i < ratingForItemID1.length; i++) {
    double rating1 = ratingForItemID1[i] - avgRatingForPreferredItem;
    double rating2 = ratingForItemID2[i] - avgRatingForRandomItem;
    numarator += rating1 * rating2;
    numitorStanga += rating1 * rating1;
    numitorDreapta += rating2 * rating2;
}

double numitor = Math.sqrt(numitorStanga * numitorDreapta);
double corelare = numarator / numitor;

Постоянный доступ к данным в памяти может быть в 5 раз быстрее, чем при произвольном доступе.

0 голосов
/ 29 января 2012

Вы можете ускорить свой алгоритм (в зависимости от используемого диапазона значений), изменив значения с плавающей запятой на длинные значения, которые масштабируются в соответствии с количеством нужных вам десятичных разрядов, то есть value * 10000 для 4 десятичных разрядов.

Если вы решили сделать это, вам нужно будет помнить о шкале деления и умножения (numitorDreapta += (diff2 * diff2) / 10000;), которая добавляет некоторый беспорядок в ваш код.

Вам понадобитсяконвертировать до и после, но если вам нужно сделать много вычислений, используя целочисленную арифметику вместо плавающей запятой, это может привести к ускорению, которое вы ищете.

...