我需要使以下代码更高效。运行时间太长。
def aFib(n: Int): BigInt = {
var nn: Int = n
var sign: Int = 0
if (nn < 0) {
nn = -nn
sign = 2 * (nn % 2) - 1
} else {
sign = 1
}
var a: BigInt = 1
var b: BigInt = 0
var p: BigInt = 0
var q: BigInt = 1
while (nn != 0) {
if (nn % 2 == 1) {
var t = (b + a) * q + a * p
b = b * p + a * q
a = t
}
var t = p * p + q * q
q =(2 * p * q) + q * q
p = t
nn /= 2
}
sign * b
}
我已经尝试了不同的方法(迭代,递归等),并决定使用代码中包含的算法。 Cognoscenti将认识到它是计算正负斐波纳契数的一种众所周知的方法。我自己编写了代码,然后放入BigInt。似乎没有快速可用的快速实现。 由于Scala是一门复杂的语言,并且我的经验有限,因此我的直觉是有一些方法可以使代码更好-减少运行时间。欢迎所有建议。
答案 0 :(得分:1)
首先,查看以下内容进行分析:https://developer.lightbend.com/blog/2018-04-09-profiling-JVM-applications/;其次,BigInt包装了java.math.BigInteger:https://github.com/scala/scala/blob/v2.12.3/src/library/scala/math/BigInt.scala#L1,这是一个任意精度的整数:https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html
因此,留在Scala中可能最好的办法是切换到本机整数类型,并且仅在数字长久变得太大时才使用此特定代码。
在这段代码中,function
可能更好地表示为位移。
最好的办法可能是使用数值计算库,并尽可能表达这些是矩阵计算,可以在gpu上并行执行:https://github.com/scalanlp/breeze
Update2:看起来Breeze似乎并没有以任何方式参与GPU:(
更新:最大的一次胜利可能是记住您的结果,因此您可以从先前的值(如果已经计算出)中计算出fibonnacci。存储这些结果,在表中查找它们,然后按照@tim的建议,在表中填充前几千个数字。
答案 1 :(得分:0)
使用惰性实现
import scala.math.BigInt
lazy val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 }
fibs.take(5).last
@弗雷德 另外,您可以对负值和正值使用类似的方法
def fib(value: Int): BigInt = {
@tailrec
def helper(cur: BigInt, prev: BigInt, n: BigInt): BigInt = {
val zero = BigInt(0)
if (n == zero) cur
else if (n > 0) helper(cur + prev, cur, n - 1)
else helper(prev, cur - prev, n + 1)
}
helper(0, 1, value)
}