(如果此前已经有人提出过这个问题,我很抱歉——我不敢相信没有人问过,但我找不到。也许是我的搜索能力太弱了。)
多年来,我一直“知道”Java没有本地函数可以缩放数组(即将每个元素乘以一个常数)。因此,我一直在做这件事:
for (int i=0; i<array.length; i++) {
array[i] = array[i] * scaleFactor;
}
这实际上是最有效的方式吗(例如在这个应用程序中,它是大约10000个双精度数组)?还是有更好的方法?
(如果此前已经有人提出过这个问题,我很抱歉——我不敢相信没有人问过,但我找不到。也许是我的搜索能力太弱了。)
多年来,我一直“知道”Java没有本地函数可以缩放数组(即将每个元素乘以一个常数)。因此,我一直在做这件事:
for (int i=0; i<array.length; i++) {
array[i] = array[i] * scaleFactor;
}
这实际上是最有效的方式吗(例如在这个应用程序中,它是大约10000个双精度数组)?还是有更好的方法?
我认为这个看起来非常好,我想不出更有效的方法了。显然,尽量将该代码放在一个地方而不是到处都是实际代码,除此之外,没有明显的问题。
我唯一能提供的建议是懒惰缩放,这意味着您只需要在访问每个元素时支付乘法成本;例如:
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;
}
}
显然,这种方法只适用于特定情况:
在其他情况下,这是一种微小的优化,在现代CPU上没有真正的好处。
array[i] *= scaleFactor;
而不是array[i] = array[i] * scaleFactor;
。:-)除了Adamski和Jon Skeet提到的内容,我想补充一点:如果它恰好是一个整数/长整数数组,并且您要缩放2的幂,则使用位移运算符可能会稍微提高性能。但是,这取决于编译器(甚至可能是虚拟机),因此可能会有所不同。
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]
在我看来,这看起来是最优的。
不要被虚假的优化所迷惑,例如在循环外部的final字段中声明数组长度。这对于集合可以避免重复调用.size()方法和字符串避免调用.length()方法,但是对于数组而言,.length已经是一个公共的final字段。
此外,向零反向循环可能是汇编语言优化,但在像Java这样的高级语言中,虚拟机会处理任何明显的微调。