递归GO vs Scala

时间:2014-07-17 05:08:31

标签: scala go fibonacci

以下Scala代码在1.5分钟内完成,而GO中的等效代码在2.5分钟内完成 最高纤维(40)都需要2秒。间隙出现在fib(50)中 我得到的印象是GO,原生,应该比Scala更快。

Scala

def fib(n:Int):Long = {
    n match {
        case 0 => 0
        case 1 => 1
        case _ => fib(n-1) + fib(n-2)
    }
}

GO

func fib(n int) (ret int) {
    if n > 1 {
        return fib(n-1) + fib(n-2)
    }
    return n
}

Scala优化?
Golang限制?

由于“我的另一辆车是一名干部”,所以问题是“在这个特殊的微基准测试中,Scala如何比GO更快?”

忘记Fibonacci让我说我确实有一个需要递归的函数 Scala在递归情况下是否优越?

它可能是内部编译器实现,甚至是Scala特定的优化 如果你知道,请回答。

在12秒内进入循环运行15000000000

func fib(n int) (two int) {
    one := 0
    two = 1
    for i := 1; i != n; i++ {
        one, two = two, (one + two)
    }
    return
}

2 个答案:

答案 0 :(得分:3)

对于Go,使用迭代而不是递归。递归可以用具有显式堆栈的迭代替换。它避免了函数调用和调用堆栈管理的开销。例如,使用迭代并将n从50增加到1000几乎不需要时间:

package main

import "fmt"

func fib(n int) (f int64) {
    if n < 0 {
        n = 0
    }
    a, b := int64(0), int64(1)
    for i := 0; i < n; i++ {
        f = a
        a, b = b, a+b
    }
    return
}

func main() {
    n := 1000
    fmt.Println(n, fib(n))
}

输出:

$ time .fib
1000 8261794739546030242
real    0m0.001s
user    0m0.000s
sys 0m0.000s

使用适当的算法。避免指数时间复杂性。当性能很重要时,不要使用递归来表示Fibonacci数。

参考:

  

Recursive Algorithms in Computer Science Courses: Fibonacci Numbers and Binomial Coefficients

     

我们观察到分支递归的计算效率低下   几乎所有的教科书都没有适当地涵盖这些功能   计算机科学课程的前三年课程。   Fibonacci数和二项式系数经常被用作   分支递归函数的例子。但是,它们呈指数增长   时间复杂性很少被宣称,并且从未完全证实   教科书。替代线性时间迭代解决方案很少   提及。我们给出了这些递归函数的非常简单的证明   具有指数时间复杂度。

     

递归是定义和算法的有效技术   只进行一次递归调用,但如果是非常低效的话   它会进行两次或多次递归调用。因此递归方法是   作为概念工具而不是作为概念工具通常更有用   高效的计算工具。本文提出的证据是   成功地教授(超过五年)到一年级学生   在渥太华大学。建议递归为   问题解决和定义工具将在第二部分中介绍   第一个计算机科学课程但是,递归编程应该   推迟到课程结束(或者更好的是在课程结束时)   迭代后的第二个计算机科学课程的开头   程序掌握得很好,堆栈操作也很好理解。

答案 1 :(得分:0)

Scala解决方案将使用堆栈,因为它不是尾递归(在递归调用之后添加),但它根本不应该创建任何垃圾。

对于这种代码模式,最常见的是你使用的热点编译器(可能是服务器)只是比Go编译器更好的编译器。

如果您真的很好奇,可以download a debug build of the JVM, and have it print out the assembly code