Ian Renton
Ian Renton

Reputation: 729

Most Efficient Way to Scale an Array in Java?

(Apologies if this has been asked before - I can't believe it hasn't, but I couldn't find one. Perhaps my search-fu is weak.)

For years I've "known" that Java has no native function to scale an array (i.e. multiply each element by a constant). So I've been doing this:

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

Is this actually the most efficient way (in this application, for example, it's an array of around 10000 doubles)? Or is there a better way?

Upvotes: 14

Views: 17688

Answers (7)

Reveille
Reveille

Reputation: 4629

In 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));

output: [3.0, 6.0, 9.0]

Upvotes: 2

vaughandroid
vaughandroid

Reputation: 4374

Only thing I can think to add in addition to Adamski and Jon Skeet is that if it happens to be an array of ints/longs and you're scaling by a power of 2, then you might get a slight improvement by using bitshift operators. YMMV though, since it will depend on the compiler (and possibly even the VM).

Upvotes: 3

ChrisWhoCodes
ChrisWhoCodes

Reputation: 640

Looks optimal to me.

Don't fall for false optimisations like declaring the array length in a final field outside the loop. This works for Collections by avoiding repeat method calls to .size() and Strings avoiding method calls to .length() but on an array .length is already a public final field.

Also, looping backwards towards zero might be an assembly language optimisation but in a high level language like Java the VM will take care of any obvious tweaks.

Upvotes: 0

Hachi
Hachi

Reputation: 3289

You could work with threads, to reduce the runtime, but the bottom line is you would include this code and let each thread run a part of the for loop so the resulting program is as efficient as yours; it's just made faster

Upvotes: 0

Mac
Mac

Reputation: 14791

The "better way" is to write array[i] *= scaleFactor; instead of array[i] = array[i] * scaleFactor;. :-)

Really, that's just syntactic sugar though - the compiled output (and hence performance) should be exactly the same. As Jon says, you're not going to be able to get any better performance, but personally I'll take a reduction in typing any day.

Upvotes: 5

Adamski
Adamski

Reputation: 54705

Only other suggestion I can offer is to lazily scale whereby you only pay the cost of multiplication on accessing each element; e.g.

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

Obviously this is only better in certain situations:

  • When your array is huge AND
  • You are only accessing a few elements AND
  • You are typically accessing these elements once.

In other situations it's a micro-optimisation with no real benefit on modern CPUs.

Upvotes: 8

Jon Skeet
Jon Skeet

Reputation: 1500525

Looks absolutely fine to me. I can't think of a more efficient way. Obviously try to put that code in one place rather than having the actual code all over the place, but other than that, no obvious problems.

Upvotes: 14

Related Questions