Scala尾递归与命令之间的行为不一致

时间:2014-08-29 13:03:51

标签: scala tail-recursion

我目前正在尝试一起学习函数式编程(和Scala)。我从FORTRAN例程移植了一些代码,用于计算相关勒让德多项式的特定修正归一化。我对原始代码的直接命令性翻译是modpLgndr1(我已根据原始算法进行了检查)。我最初尝试以函数形式编写代码是在modpLgdnr2中。

import math.pow, abs, sqrt, Pi

def xfact(m: Int): Double = {
  if (m <= 1) 1.0
  else {
    if (m % 2 == 1) m.toDouble / sqrt(m.toDouble) * xfact(m - 1)
    else 1.0 / sqrt(m.toDouble) * xfact(m - 1)
  }
}

//this is a very un-scala function....
def modpLgndr1(l: Int, m: Int, x: Double): Double = {
  assert(0 <= m && m <= l && abs(x) <= 1.0)
  val dl = l.toDouble
  val dm = m.toDouble
  val norm = sqrt(2.0 * dl + 1.0) / sqrt(4.0 * Pi)
  var pmm = norm
  if (m != 0) pmm = (pow(-1, m)).toDouble * pmm * xfact(2 * m) * pow((1.0-x * x), (dm / 2.0))
  if (l == m) pmm
  else {
    var pmmp1 = x * pmm * sqrt(2.0 * m + 1.0)
    if (l == m + 1) pmmp1
    else {
      var pll = 0.0
      var dll = 0.0
      for (ll <- m + 2 to l) {
        dll = ll.toDouble
        pll = (x * (2.0 * dll - 1.0) * pmmp1 - sqrt(pow((dll - 1.0), 2.0) - dm * dm) * pmm) / sqrt(pow(dll, 2.0) - pow(dm, 2.0))
        pmm = pmmp1
        pmmp1 = pll
      }
      pll
    }
  }
}

def modpLgndr2(l: Int, m: Int, x: Double): Double = {
  assert(0 <= m && m <= l && abs(x) <= 1.0)
  val dl = l.toDouble
  val dm = m.toDouble
  val norm = sqrt(2.0 * dl + 1.0) / sqrt(4.0 * Pi)
  val pmm = if (m == 0) norm else (pow(-1, m)).toDouble * norm * xfact(2 * m) * pow((1.0-x * x), (dm / 2.0))
  if (l == m) pmm
  else {
    val pmmp1 = x * pmm * sqrt(2.0 * m + 1.0)
    if (l == m + 1) pmmp1
    else {
      def mplacc(ll: Int, acc1: Double, acc2: Double): Double = {
        val dll = ll.toDouble
        val pll = (x * (2.0 * dll - 1.0) * acc2 - sqrt(pow((dll - 1.0), 2.0) - dm * dm) * acc1) / sqrt(pow(dll, 2.0) - pow(dm, 2.0))
        if (ll == m + 2) pll
        else mplacc(ll - 1, acc2, pll)
      }
      mplacc(l, pmm, pmmp1)
    }
  }
}

如果我调用这两个函数,我会得到如下输出:

scala> for (i <- 0 to 10) println(modpLgndr1(10,i,0.2))

0.16685408398957746 -0.2769345073769805 -0.1575129272628402 0.2948210515201088 0.12578847877176355 -0.3292975894931367 -0.058267280378036426 0.37448134558730417 -0.08024600262585084 -0.40389602261165075 0.4424459249420354

scala> for (i <- 0 to 10) println(modpLgndr2(10,i,0.2))

0.16685408398957752 -0.2772969351441124 -0.1578618478786792 0.29654926805696474 0.1349402872678466 -0.33707342609134694 -0.06901634276825179 0.38912154672892657 -0.08024600262585084 -0.40389602261165075 0.4424459249420354

基本上,对于m = 0,l-2,l-1,l代码同意;否则存在显着差异。这似乎告诉我问题在于调用mplacc函数。对我来说,mplacc看起来像是modpLgndr1中for循环的递归形式。为什么我错了?

0 个答案:

没有答案