C# 关于比奈公式的Smth

C# 关于比奈公式的Smth,c#,time-complexity,fibonacci,C#,Time Complexity,Fibonacci,为什么比奈公式(O(LogN)在时间上不如迭代法(O(n)) static long[]NumbersFibonacci=new long[35]; 公共静态无效Iteracii(内部n) { 数字斐波那契[0]=0; 数字斐波那契[1]=1; 对于(int i=1;i

为什么比奈公式(O(LogN)在时间上不如迭代法(O(n))

static long[]NumbersFibonacci=new long[35];
公共静态无效Iteracii(内部n)
{
数字斐波那契[0]=0;
数字斐波那契[1]=1;
对于(int i=1;i

如果假定算术运算为O(1),则使用比奈公式为O(1),典型的迭代实现为O(n)

然而,如果我们假设算术运算是O(1),那么,即使
fibo(n)
是一个常见的访谈和电话屏幕主题,实际上以典型的方式实现它是没有意义的——除非被告知我们要忽略标准编程语言整数和浮点数的有限性。斐波那契数呈指数增长。它们溢出标准编程语言类型很久以前就选择了特定的算法,只要是一个没有选择朴素的递归实现

具体来说,这里有两个在C#中返回第n个斐波那契数的实现。最上面的一个在double上实现了Binet的封闭形式解决方案,并将其转换为long,在C#中,long将是64位宽。第二个是迭代版本:

static long constant_time_fibo(long n)
{
    double sqrt_of_five = Math.Sqrt(5.0);
    return (long) (
        (Math.Pow(1.0 + sqrt_of_five, n) - Math.Pow(1.0 - sqrt_of_five, n)) /
        (sqrt_of_five * Math.Pow(2.0, n))
    );
}
 
static long linear_time_fibo(long n)
{
    long previous = 0;
    long current = 1;
    for (int i = 1; i < n; i++)
    {
        long temp = current;
        current = previous + current;
        previous = temp;
    }
    return current;
}
 
static void Main(string[] args)
{
    for (int i = 1; i < 100; i++)
        Console.WriteLine("{0} => {1} {2}", i, 
            constant_time_fibo(i), linear_time_fibo(i) );
}
static long constant\u time\u fibo(长n)
{
double sqrt_of_five=Math.sqrt(5.0);
返回(长)(
(Math.Pow(1.0+sqrt_of theu five,n)-Math.Pow(1.0-sqrt_of theu five,n))/
(五分之二*数学功率(2.0,n))
);
}
静态长线性时间fibo(长n)
{
长前=0;
长电流=1;
对于(int i=1;i{1}{2}”,i,
常数时间fibo(i),线性时间fibo(i);
}
当我运行这段代码时,由于浮点错误,常数时间算法在n=72左右无法匹配迭代实现,而迭代方法在n=92左右由于溢出而失败。如果我使用32位类型而不是64位类型,这种情况会发生得更快

九十二项不算什么。如果你在实践中需要第n个斐波那契数,并且只关心适合64位的斐波那契数,在一个非人为的情况下——不是为了家庭作业或白板问题——它应该花费O(1)个时间,这不是因为比奈公式的存在,而是因为你应该使用一个包含92项的查找表。在C++中,你甚至可以在编译时生成92个条目,使用<代码> CONTXPRP</C>函数。
另一方面,如果我们讨论的是任意大数算术,那么这个问题就更有趣了。比奈公式中的指数都是整数。你可以只使用任意大的整数运算来实现比奈的公式-你不需要计算任何5的平方根,只需要跟踪“5的平方根在哪里”,因为它们最终会抵消。你用二项式的形式计算,比如(a+b)√5) /c但由于φ的奇怪代数性质,所有的非理性和所有的非整数数学都被魔法抵消了。您不需要实际计算任何√5的时间,同时查找ν^n。如果使用“”,这将导致一个O(logn)实现——无论如何,O(logn)算术运算;整个过程的时间复杂度取决于您使用的任意大型算术库的时间复杂度。

一次运行无法准确估计。特别是因为在内存中加载代码(“冷启动”)会花费更多的时间。请尝试在大量数据中加载代码。for循环增加了一定程度的低效率。@WillemVanOnsem问题不是“冷启动”。当然,在1-2次迭代后,时间会变短,但算法执行时间之间的比率不会有太大变化。@jdweng当n增加时,迭代方法的时间会逐渐增加。但是对于比奈公式,它看起来像一个常数。我不明白为什么。@Runn1ng:如果你交换这两个算法,那么首先是
Iteracii
,然后是
Bine
static long[] NumbersFibonacci = new long[35];
public static void Iteracii(int n)
{
NumbersFibonacci[0] = 0;
NumbersFibonacci[1] = 1;
for (int i = 1; i < n - 1; i++)
    {
        NumbersFibonacci[i + 1] = NumbersFibonacci[i] + NumbersFibonacci[i - 1];
    }
}
static long constant_time_fibo(long n)
{
    double sqrt_of_five = Math.Sqrt(5.0);
    return (long) (
        (Math.Pow(1.0 + sqrt_of_five, n) - Math.Pow(1.0 - sqrt_of_five, n)) /
        (sqrt_of_five * Math.Pow(2.0, n))
    );
}
 
static long linear_time_fibo(long n)
{
    long previous = 0;
    long current = 1;
    for (int i = 1; i < n; i++)
    {
        long temp = current;
        current = previous + current;
        previous = temp;
    }
    return current;
}
 
static void Main(string[] args)
{
    for (int i = 1; i < 100; i++)
        Console.WriteLine("{0} => {1} {2}", i, 
            constant_time_fibo(i), linear_time_fibo(i) );
}