2

このスプライン補間アルゴリズムを Java の apache.commons.math から Scala に、考えられる最も簡単な方法で変換しました (以下を参照) 。最終的に得られた関数は、元の Java コードよりも 2 倍から 3 倍遅く実行されます。私の推測では、この問題は への呼び出しに起因する余分なループが原因であると推測されますがArray.fill、それらを取り除く簡単な方法は思いつきません。このコードのパフォーマンスを向上させる方法について何か提案はありますか? (より簡潔かつ/または機能的な方法で書くこともいいでしょう-その面での提案も高く評価されます.)

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))))
}
4

1 に答える 1

6

Array.fill新しい配列は、値であるか参照であるかに応じて、常に0またはnullで初期化されるため、すべてを取り除くことができます(ブール値はfalseで初期化され、文字はで初期化されます\0)。

配列を圧縮することでループを単純化できるかもしれませんが、遅くなるだけです。Stream関数型プログラミング(とにかくJVM上で)がこれを高速化するのに役立つ唯一の方法は、またはビューなどで非厳密にした後、先に進んですべてを使用しない場合です。

于 2013-01-15T04:04:32.923 に答える