摆脱Scala中的for循环
这里有一个问题涉及到一个阶乘。对于给定的数字,摆脱Scala中的for循环,scala,functional-programming,Scala,Functional Programming,这里有一个问题涉及到一个阶乘。对于给定的数字,n,请找到以下问题的答案: (1 / n!) * (1! + 2! + 3! + ... + n!) Scala中的迭代解非常简单——一个简单的for循环就足够了 object MyClass { def fsolve(n: Int): Double = { var a: Double = 1 var cum: Double = 1 for (i <- n to 2 by -1) { a = a *
n
,请找到以下问题的答案:
(1 / n!) * (1! + 2! + 3! + ... + n!)
Scala中的迭代解非常简单——一个简单的for循环就足够了
object MyClass {
def fsolve(n: Int): Double = {
var a: Double = 1
var cum: Double = 1
for (i <- n to 2 by -1) {
a = a * (1.0/i.toDouble)
cum += a
}
scala.math.floor(cum*1000000) / 1000000
}
def main(args: Array[String]) {
println(fsolve(7)) // answer 1.173214
}
有任何解决方案的建议或指针吗?结果从
foldLeft
返回,如下所示:
val cum = (n to 2 by -1).foldLeft(1.toDouble) (_*_)
只有在您的情况下,函数才需要不同,因为上面的折叠会将所有i
值相乘。您将传递折叠的cum
和a
值:
def fsolve(n: Int): Double = {
val (cum, _) = (n to 2 by -1).foldLeft(1.0, 1.0) { case ((sum, a),i) =>
val newA = a * (1.0/i.toDouble)
(sum + newA, newA)
}
scala.math.floor(cum*1000000) / 1000000
}
结果从
foldLeft
返回,如下所示:
val cum = (n to 2 by -1).foldLeft(1.toDouble) (_*_)
只有在您的情况下,函数才需要不同,因为上面的折叠会将所有i
值相乘。您将传递折叠的cum
和a
值:
def fsolve(n: Int): Double = {
val (cum, _) = (n to 2 by -1).foldLeft(1.0, 1.0) { case ((sum, a),i) =>
val newA = a * (1.0/i.toDouble)
(sum + newA, newA)
}
scala.math.floor(cum*1000000) / 1000000
}
我将尝试实现一个解决方案,但不填补空白,而是提出一种不同的方法
def fsolve(n: Int): Double = {
require(n > 0, "n must be positive")
def f(n: Int): Long = (1 to n).fold(1)(_ * _)
(1.0 / f(n)) * ((1 to n).map(f).sum)
}
在函数中,我使用require
确保无效输入失败,我定义阶乘(如f
),然后使用它,只需以最接近我们想要实现的原始表达式的方式写下函数:
(1.0 / f(n)) * ((1 to n).map(f).sum)
如果确实要显式折叠,可以按如下方式重写此表达式:
(1.0 / f(n)) * ((1 to n).map(f).fold(0L)(_ + _))
另外,请注意,由于您正在执行的所有操作(求和和和乘法)都是可交换的,因此可以使用fold
而不是foldLeft
:使用前者不会规定操作的运行顺序,从而允许集合的特定实现并行运行计算
您可以随意使用这段代码。我将尝试实现一个解决方案,但不填补空白,而是提出一种不同的方法
def fsolve(n: Int): Double = {
require(n > 0, "n must be positive")
def f(n: Int): Long = (1 to n).fold(1)(_ * _)
(1.0 / f(n)) * ((1 to n).map(f).sum)
}
在函数中,我使用require
确保无效输入失败,我定义阶乘(如f
),然后使用它,只需以最接近我们想要实现的原始表达式的方式写下函数:
(1.0 / f(n)) * ((1 to n).map(f).sum)
如果确实要显式折叠,可以按如下方式重写此表达式:
(1.0 / f(n)) * ((1 to n).map(f).fold(0L)(_ + _))
另外,请注意,由于您正在执行的所有操作(求和和和乘法)都是可交换的,因此可以使用fold
而不是foldLeft
:使用前者不会规定操作的运行顺序,从而允许集合的特定实现并行运行计算
您可以使用此代码。您提供的公式很好地映射到
scanleet
函数。它的工作原理有点像foldLeft
和map
的组合,运行折叠操作,但将生成的每个值存储在输出列表中。下面的代码生成从1
到n
的所有阶乘,将它们相加,然后除以n代码>。请注意,通过在末尾执行单个浮点除法,而不是在每个中间步骤,可以降低浮点错误的几率
def fsolve(n: Int): Double =
{
val factorials = (2 to n).scanLeft(1)((cum: Int, value: Int) => value*cum)
scala.math.floor(factorials.reduce(_+_)/factorials.last.toDouble*1000000)/1000000
}
您提供的公式很好地映射到scanLeft
函数。它的工作原理有点像foldLeft
和map
的组合,运行折叠操作,但将生成的每个值存储在输出列表中。下面的代码生成从1
到n
的所有阶乘,将它们相加,然后除以n代码>。请注意,通过在末尾执行单个浮点除法,而不是在每个中间步骤,可以降低浮点错误的几率
def fsolve(n: Int): Double =
{
val factorials = (2 to n).scanLeft(1)((cum: Int, value: Int) => value*cum)
scala.math.floor(factorials.reduce(_+_)/factorials.last.toDouble*1000000)/1000000
}
请注意:由于阶乘的计算方式,此解决方案的复杂性为O(N^2)。原始代码是O(N)。这可能是一个问题,也可能不是,这取决于使用情况。请注意:由于阶乘的计算方式,此解决方案的复杂性为O(N^2)。原始代码是O(N)。这可能是问题,也可能不是问题,具体取决于使用情况。此解决方案适用于大数字和小数字,例如200。谢谢。此解决方案适用于大数字和小数字,例如200。非常感谢。