我目前正在尝试一起学习函数式编程(和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循环的递归形式。为什么我错了?