【问题标题】:Why is this Fibonacci code not correct? [closed]为什么这个斐波那契代码不正确? [关闭]
【发布时间】:2013-10-15 15:48:52
【问题描述】:

欧拉计划问题 2。

斐波那契数列中的每个新项都是通过添加前两项来生成的。从 1 和 2 开始,前 10 个术语将是:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

通过考虑斐波那契数列中值不超过四百万的项,求偶数项之和。

我的解决方案:

int firstNum = 1;
int secondNum = 2;
int resultNum = firstNum + secondNum;
int sum = 0;

for (int i = 0; i < 4000000; i++)
{
    firstNum = i;
    secondNum = i;

    if(resultNum == firstNum + secondNum)
    {
        sum += resultNum;
        Console.WriteLine(sum);
    }
}

为什么这不正确,您能引导我进入正确的思维方式吗?

【问题讨论】:

  • 只调试你的代码。当你看到它在前几个循环中做了什么时,我认为应该很清楚。
  • 您的firstNumsecondNum 在每种情况下都只是iresultNum 将始终为 3。因此,您正在寻找 i 的任何整数值,使得 i + i 为 3。这不会产生很多答案。您的代码目前根本不产生斐波那契数...
  • 您的代码没有创建斐波那契数列。先把那部分弄清楚。
  • @AdamV 问题描述具体指定从1,2开始。
  • @RealityDysfunction 斐波那契实际上是一个使用递归的非常糟糕的问题。除非您缓存这些值或使用动态编程,否则您最终会一遍又一遍地重新计算相同的值,从而将可能是线性的算法变成指数的算法。计算高达 400 万的值实际上已经足够大,以至于幼稚的递归实现很难计算出结果。

标签: c# fibonacci


【解决方案1】:

试试这个:

    int n1, n2, fib;
        //n1 = 0;
        //n2 = 1;
        n1 = 1;
        n2 = 1;

        fib = n1 + n2;

        while (fib < 4000000)
        {

            n2 = n1;
            n1 = fib;
            fib = n1 + n2;
        }

然后找到偶数并求和

【讨论】:

    【解决方案2】:

    对于更模块化的方法(与 LINQ 混合):

    IEnumerable<Int32> Fibonacci(Int32 limit = 4000000)
    {
        for (Int32 previous = 0, current = 1, next = 0; 
            current <= limit; current = next)
        {
            next = previous + current;
            previous = current;
            yield return next;
        }
    }
    

    然后:

    var allNumbers = Fibonacci(4000000); // 1,2,3,5,8,13,21
    var evenNumbers = allNumbers.Where(x => x % 2 == 0); // 2,8,34,144,610,2584
    var sum = evenNumbers.Sum(); // 4613732
    

    【讨论】:

    • 1) 你真的应该使用更有意义的变量名。 2) OP 的要求是从 1,2,而不是 0,1 开始。 3) 这并不能帮助 OP 理解他做错了什么,它只是在为他做他的工作 4) 以他的技能水平的人不太可能能够有效地理解迭代器块以使用它们。
    • @Servy:在我发布这个问题之前,这个问题已经有了一个公认的答案,所以我并没有真正寻求全面的解决方案。我所做的只是提供一个更模块化的答案,并展示如何使用 LINQ 和方法调用来执行此操作(而不是将所有内容都堆积到单个可执行路径中)。不过还是感谢你们的 cmets。
    • 第一点可能比其他任何事情都更困扰我。如果您只想展示如何“正确执行”,那么您当前的变量名称会使代码几乎不可读这一事实阻碍了您。
    • @Servy:从来没有说过“做对了”;你是在暗示。我所说的只是更加模块化。如果我是为了可读性,我不会停留在变量名上——除了在标题中添加注释块之外,我还会使方法和变量名更简洁。但是您有足够的代表,请随时编辑您满意的答案。
    【解决方案3】:

    斐波那契数列定义为

    A0 = 1, A1 = 1

    An = An-1 + An-2

    你的目标是产生模式

    1 2 3 5 8 13 等

    在迭代时,您将需要调整类似于滑动窗口的输入,然后检查是否遇到有效插入(即

    int sum = 0;
    int max = 4000000;
    for( int n = 0; n < max ; n++ )
    {
     //only sum the even numbers
     if( second % 2 == 0 ) sum += second; 
    
     //adjust
     int result = first + second;
     first = second;
     second = result;
    
     //test for numbers greater than max
     if( result > max ) break;
    }
    
    //output
    Console.WriteLine(sum); //An for all even An values
    

    希望在查看此内容后,您可以看到遇到的一些问题。

    您将变量设置为迭代器 i,它不会产生定义的 An 而是完全不同的东西。

    firstNum = i;
    secondNum = i;
    

    此外,您只需计算一次结果。这需要在循环中完成。只计算一次基本上会一直使用静态值。

    int resultNum = firstNum + secondNum;
    

    条件语句应该测试偶数以正确添加到总和中,但此代码只会测试resultNum的静态值

    if(resultNum == firstNum + secondNum)
    

    此外,需要对总和进行一些检查,以便在超过最大值时突破。 4M 迭代太多了。


    不过,这里可以进行更多优化。查看 for 循环,很明显,虽然尚未使用,但迭代器可以是一个强大的工具。

    原因是斐波那契符合“黄金比例”。

    通过简单观察斐波那契数列在 3 次迭代中达到偶数,迭代器可用于跳过该数列。

    double p = (1 + Math.Pow(5,.5)) / 2;
    for( int n = 3, sum = 0;;n+=3)
    {
     double f = ( Math.Pow(p,n) - Math.Pow( 1 - p , n ) ) / Math.Pow(5,.5);
     if( f > 4000000 ){ 
      Console.WriteLine(sum);
      break;
     }
     sum += (int)Math.Round(f);
    }
    

    【讨论】:

    • 问题描述中特别指出是从1、2开始,而不是1、1。
    • 他不想计算 400 万个 fib 数字,而是要计算最多 400 万个数字。 差别很大
    • @Servy - 我错过了那个警告,进行了编辑。
    • 您仍在调用变量maxIterations,但它在逻辑上并不代表最大迭代次数。从逻辑上讲,for 循环根本不适合开始的任务。它应该是一个while 循环。因为它是您的for 循环,所以也可能只是for(;;),因为 n 从未用于任何事情,并且您总是在达到结束条件之前中断。
    • @TravisJ 我不是说你应该有一个for(;;) 循环,我是说你的 for 循环中的代码毫无意义。我特别建议您使用 while 循环,因为它避免了无意义的代码,同时实际上在语义上代表了您正在做的事情。
    【解决方案4】:

    您的代码不会产生斐波那契数列,也不会检查偶数项

    试试这个

    int firstNum = 1;
    int secondNum = 2;
    
    int sum = 0;
    
    while (secondNum <= 4000000)
    {
        if (secondNum % 2 == 0)
            sum += secondNum;
    
        int resultNum = firstNum + secondNum;
        firstNum = secondNum;
        secondNum = resultNum;
    }
    
    Console.WriteLine(sum);
    

    【讨论】:

      猜你喜欢
      • 2012-12-29
      • 2018-06-15
      • 1970-01-01
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-21
      相关资源
      最近更新 更多