Reputation: 729
(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
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
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
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
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
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
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:
In other situations it's a micro-optimisation with no real benefit on modern CPUs.
Upvotes: 8
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