Scala与Java中样条插值的性能比较

Scala与Java中样条插值的性能比较,java,performance,scala,interpolation,spline,Java,Performance,Scala,Interpolation,Spline,我用我能想到的最直接的方式将apache.commons.math从Java翻译成Scala(见下文)。我最终得到的函数运行速度比原始Java代码慢2到3倍。我的猜测是,问题源于对Array.fill的调用所产生的额外循环,但我想不出一个简单的方法来消除它们。关于如何使此代码性能更好,有什么建议吗?(如果能以更简洁和/或更实用的方式编写,也会很好——我们也希望能就此提出建议。) type Real=Double def mySplineInterpolate(x:Array[Real],y:Ar

我用我能想到的最直接的方式将apache.commons.math从Java翻译成Scala(见下文)。我最终得到的函数运行速度比原始Java代码慢2到3倍。我的猜测是,问题源于对
Array.fill
的调用所产生的额外循环,但我想不出一个简单的方法来消除它们。关于如何使此代码性能更好,有什么建议吗?(如果能以更简洁和/或更实用的方式编写,也会很好——我们也希望能就此提出建议。)

type Real=Double
def mySplineInterpolate(x:Array[Real],y:Array[Real])={
如果(x.长度!=y.长度)
抛出新尺寸不匹配异常(x.length,y.length)
如果(x.长度<3)
抛出新的NumberStooSmallException(x.length,3,true)
//间隔数。数据点数为n+1。
val n=x.长度-1
//结点之间的差异
val h=数组。制表(n)(i=>x(i+1)-x(i))
var mu:Array[Real]=Array.fill(n)(0)
var z:Array[Real]=Array.fill(n+1)(0)
变量i=1
而(i=0){
c(j)=z(j)-mu(j)*c(j+1)
b(j)=(y(j+1)-y(j))/h(j)-h(j)*(c(j+1)+2.0*c(j))/3.0
d(j)=(c(j+1)-c(j))/(3.0*h(j))
j-=1
}
表列(n)(i=>多项式(数组(y(i),b(i),c(i),d(i)))
}

您可以去掉所有的
数组。填充
,因为新数组总是初始化为0或null,这取决于它是值还是引用(布尔值初始化为false,字符初始化为
\0


通过压缩数组,您可能可以简化循环,但这只会使循环变得更慢。函数式编程(无论如何,在JVM上)能够帮助您加快速度的唯一方法是,如果您将其设置为非严格的,例如使用
或视图,然后继续使用,而不是全部使用。

scala是构建在java之上的,因此它不会更快也就不足为奇了。不,scala是构建在JVM之上的,编译器可以直接发出JVM字节码。此外,Scala的速度通常与Java相同,并且在某些情况下(例如,在使用专门化时)更快。然而,为了获得同等速度的代码,有时必须编写非惯用的Scala。我建议OP评测他的代码,看看在Scala和Java代码中花了多少时间。好的,替换
数组。用
数组填充
s。ofDim
s几乎可以恢复Java版本的性能。谢谢。@davidsd我在那里没有看到任何多维数组。一个简单的
新数组[Real](n)
应该就足够了,尽管直到现在我才看到您使用的是
Real
,而不是
Double
.Ack--我应该在上面的代码中包含这个,但我现在正在使用
type Real=Double
Array.ofDim[Real](n)
newarray[Real](n)
之间有什么区别?@davidsd该
ofDim
方法只适用于多维数组——我很惊讶它竟然存在一个一维版本。不过,它是根据
新数组
实现的,因此您只需使用它添加一个额外的间接层。
type Real = Double

def mySplineInterpolate(x: Array[Real], y: Array[Real]) = {

  if (x.length != y.length)
    throw new DimensionMismatchException(x.length, y.length)

  if (x.length < 3)
    throw new NumberIsTooSmallException(x.length, 3, true)

  // Number of intervals.  The number of data points is n + 1.                                                                         
  val n = x.length - 1

  // Differences between knot points                                                                                                   
  val h = Array.tabulate(n)(i => x(i+1) - x(i))

  var mu: Array[Real] = Array.fill(n)(0)
  var z: Array[Real] = Array.fill(n+1)(0)
  var i = 1
  while (i < n) {
    val g = 2.0 * (x(i+1) - x(i-1)) - h(i-1) * mu(i-1)
    mu(i) = h(i) / g
    z(i) = (3.0 * (y(i+1) * h(i-1) - y(i) * (x(i+1) - x(i-1))+ y(i-1) * h(i)) /
            (h(i-1) * h(i)) - h(i-1) * z(i-1)) / g
    i += 1
  }

  // cubic spline coefficients --  b is linear, c quadratic, d is cubic (original y's are constants)                                   
  var b: Array[Real] = Array.fill(n)(0)
  var c: Array[Real] = Array.fill(n+1)(0)
  var d: Array[Real] = Array.fill(n)(0)

  var j = n-1
  while (j >= 0) {
    c(j) = z(j) - mu(j) * c(j + 1)
    b(j) = (y(j+1) - y(j)) / h(j) - h(j) * (c(j+1) + 2.0 * c(j)) / 3.0
    d(j) = (c(j+1) - c(j)) / (3.0 * h(j))
    j -= 1
  }

  Array.tabulate(n)(i => Polynomial(Array(y(i), b(i), c(i), d(i))))
}