Самый эффективный способ масштабирования массива в Java? - PullRequest
13 голосов
/ 17 октября 2011

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

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

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

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

Ответы [ 7 ]

13 голосов
/ 17 октября 2011

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

8 голосов
/ 17 октября 2011

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

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

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

  • Когда ваш массив огромен И
  • Вы получаете доступ только к нескольким элементам И
  • Как правило, вы получаете доступ к этим элементам один раз.

В других ситуациях это микрооптимизация, не приносящая реальных преимуществ современным ЦП.

5 голосов
/ 17 октября 2011

«Лучший способ» - написать array[i] *= scaleFactor; вместо array[i] = array[i] * scaleFactor;.: -)

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

3 голосов
/ 17 октября 2011

Единственное, что я могу добавить в дополнение к Адамски и Джону Скиту, это то, что если это массив массивов / длин и вы масштабируете на степень 2, то вы можете получить небольшое улучшение, используя операторы битшифта. YMMV, хотя, так как это будет зависеть от компилятора (и, возможно, даже от виртуальной машины).

1 голос
/ 10 октября 2017

В Java 8:

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

System.out.println(Arrays.toString(x2));

вывод: [3.0, 6.0, 9.0]

0 голосов
/ 17 октября 2011

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

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

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

0 голосов
/ 17 октября 2011

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

...