Самый эффективный способ масштабирования массива на Java?

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

В течение многих лет я "знал", что Java не имеет встроенной функции для масштабирования массива (т.е. умножает каждый элемент на константу). Поэтому я делаю это:

for (int i=0; i<array.length; i++) {
  array[i] = array[i] * scaleFactor;
}

Действительно ли это самый эффективный способ (в этом приложении, например, это массив около 10000 удваивается)? Или есть лучший способ?

Ответ 1

Похоже на меня. Я не могу придумать более эффективный способ. Очевидно, постарайтесь поставить этот код в одном месте, вместо того, чтобы иметь реальный код повсюду, но кроме этого, никаких очевидных проблем.

Ответ 2

Только другое предложение, которое я могу предложить, - это ленивый масштаб, при котором вы платите только стоимость умножения при доступе к каждому элементу; например.

public class MyArray {
  private final double[] arr;
  private double scale = 1.0;

  public MyArray(double[] arr) {
    this.arr = arr;
  }

  public double getScale() {
    return scale;
  }

  public void setScale(double scale) {
    this.scale = scale;
  }

  public double elementAt(int i) {
    return arr[i] * scale;
  }
}

Очевидно, что это только лучше в определенных ситуациях:

  • Когда массив массивный И
  • Вы получаете доступ только к нескольким элементам AND
  • Обычно вы обращаетесь к этим элементам один раз.

В других ситуациях это микро-оптимизация без реальной выгоды от современных процессоров.

Ответ 3

"Лучшим способом" является запись array[i] *= scaleFactor; вместо array[i] = array[i] * scaleFactor;.: -)

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

Ответ 4

Единственное, что я могу добавить в дополнение к Adamski и Jon Skeet, - это то, что если это массив массивов ints/longs, и вы масштабируетесь по мощности 2, то вы можете получить небольшое улучшение, используя операторы битрейта. YMMV, хотя, поскольку он будет зависеть от компилятора (и, возможно, даже от виртуальной машины).

Ответ 5

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

Ответ 6

Мне кажется оптимальным.

Не поддавайтесь ложным оптимизациям, таким как объявление длины массива в конечном поле вне цикла. Это работает для коллекций, избегая повторных вызовов методов в .size() и Strings, избегая вызовов методов в .length(), но в массиве .length уже является общедоступным конечным полем.

Кроме того, цикл назад к нулю может быть оптимизацией на языке ассемблера, но на языке высокого уровня, таком как Java, VM позаботится о любых очевидных трюках.

Ответ 7

В Java 8:

double coef = 3.0;
double[] x1 = {1,2,3};
double[] x2 = DoubleStream.of(x1).map(d->d*coef).toArray();