确定数字是否是斐波纳契数

时间:2010-06-29 10:05:33

标签: java fibonacci

我需要编写一个Java代码来检查用户输入的数字是否在Fibonacci序列中。

我没有问题写Fibonacci序列输出,但(可能是因为它深夜)我正在努力想到“是否”它是斐波纳契数的序列。我一遍又一遍地开始。它确实在我的脑海里。

我现在拥有的是第n个。

public static void main(String[] args)
{
    ConsoleReader console = new ConsoleReader();

    System.out.println("Enter the value for your n: ");
    int num = (console.readInt());
    System.out.println("\nThe largest nth fibonacci: "+fib(num));
    System.out.println();
}

static int fib(int n){
    int f = 0;
    int g = 1;
    int largeNum = -1;
    for(int i = 0; i < n; i++)
    {
      if(i == (n-1))
          largeNum = f;
      System.out.print(f + " ");
      f = f + g;
      g = f - g;
    }
    return largeNum;
}

14 个答案:

答案 0 :(得分:28)

阅读wikipedia上标题为“识别斐波纳契数字”的部分。

  

或者,正整数z是斐波纳契数,当且仅当5z ^ 2 + 4或5z ^ 2-4中的一个是完美平方时。[17]

或者,您可以继续生成斐波那契数字,直到一个等于您的数字:如果是,那么您的数字是斐波那契数字,如果不是,数字最终会变得比您的数字更大,您可以停止。然而,这是非常低效的。

答案 1 :(得分:10)

如果我理解正确,你需要做什么(而不是写出第一个 n Fibonacci数字)是确定 n 是否是斐波纳契数。

所以你应该修改你的方法以保持生成Fibonacci序列,直到得到一个数字&gt; = n。如果它等于, n 是斐波纳契数,否则不是。

@ Moron一再声称基于公式的算法在性能上优于上面的简单算法,但实际上我做了一个基准比较 - 具体地说是Jacopo的解决方案之间的生成器算法

更新:
和StevenH的最后一个版本为基于公式的算法。作为参考,这里是确切的代码:

public static void main(String[] args) {
    measureExecutionTimeForGeneratorAlgorithm(1);
    measureExecutionTimeForFormulaAlgorithm(1);

    measureExecutionTimeForGeneratorAlgorithm(10);
    measureExecutionTimeForFormulaAlgorithm(10);

    measureExecutionTimeForGeneratorAlgorithm(100);
    measureExecutionTimeForFormulaAlgorithm(100);

    measureExecutionTimeForGeneratorAlgorithm(1000);
    measureExecutionTimeForFormulaAlgorithm(1000);

    measureExecutionTimeForGeneratorAlgorithm(10000);
    measureExecutionTimeForFormulaAlgorithm(10000);

    measureExecutionTimeForGeneratorAlgorithm(100000);
    measureExecutionTimeForFormulaAlgorithm(100000);

    measureExecutionTimeForGeneratorAlgorithm(1000000);
    measureExecutionTimeForFormulaAlgorithm(1000000);

    measureExecutionTimeForGeneratorAlgorithm(10000000);
    measureExecutionTimeForFormulaAlgorithm(10000000);

    measureExecutionTimeForGeneratorAlgorithm(100000000);
    measureExecutionTimeForFormulaAlgorithm(100000000);

    measureExecutionTimeForGeneratorAlgorithm(1000000000);
    measureExecutionTimeForFormulaAlgorithm(1000000000);

    measureExecutionTimeForGeneratorAlgorithm(2000000000);
    measureExecutionTimeForFormulaAlgorithm(2000000000);
}

static void measureExecutionTimeForGeneratorAlgorithm(int x) {
    final int count = 1000000;
    final long start = System.nanoTime();
    for (int i = 0; i < count; i++) {
        isFibByGeneration(x);
    }
    final double elapsedTimeInSec = (System.nanoTime() - start) * 1.0e-9;
    System.out.println("Running generator algorithm " + count + " times for " + x + " took " +elapsedTimeInSec + " seconds");
}

static void measureExecutionTimeForFormulaAlgorithm(int x) {
    final int count = 1000000;
    final long start = System.nanoTime();
    for (int i = 0; i < count; i++) {
        isFibByFormula(x);
    }
    final double elapsedTimeInSec = (System.nanoTime() - start) * 1.0e-9;
    System.out.println("Running formula algorithm " + count + " times for " + x + " took " +elapsedTimeInSec + " seconds");
}

static boolean isFibByGeneration(int x) {
    int a=0;
    int b=1;
    int f=1;
    while (b < x){
        f = a + b;
        a = b;
        b = f;
    }
    return x == f;
}

private static boolean isFibByFormula(int num) {
    double first = 5 * Math.pow((num), 2) + 4;
    double second = 5 * Math.pow((num), 2) - 4;

    return isWholeNumber(Math.sqrt(first)) || isWholeNumber(Math.sqrt(second));
}

private static boolean isWholeNumber(double num) {
    return num - Math.round(num) == 0;
}

结果甚至让我感到惊讶:

Running generator algorithm 1000000 times for 1 took 0.007173537000000001 seconds
Running formula algorithm 1000000 times for 1 took 0.223365539 seconds
Running generator algorithm 1000000 times for 10 took 0.017330694 seconds
Running formula algorithm 1000000 times for 10 took 0.279445852 seconds
Running generator algorithm 1000000 times for 100 took 0.030283179 seconds
Running formula algorithm 1000000 times for 100 took 0.27773557800000004 seconds
Running generator algorithm 1000000 times for 1000 took 0.041044322 seconds
Running formula algorithm 1000000 times for 1000 took 0.277931134 seconds
Running generator algorithm 1000000 times for 10000 took 0.051103143000000004 seconds
Running formula algorithm 1000000 times for 10000 took 0.276980175 seconds
Running generator algorithm 1000000 times for 100000 took 0.062019335 seconds
Running formula algorithm 1000000 times for 100000 took 0.276227007 seconds
Running generator algorithm 1000000 times for 1000000 took 0.07422898800000001 seconds
Running formula algorithm 1000000 times for 1000000 took 0.275485013 seconds
Running generator algorithm 1000000 times for 10000000 took 0.085803922 seconds
Running formula algorithm 1000000 times for 10000000 took 0.27701090500000003 seconds
Running generator algorithm 1000000 times for 100000000 took 0.09543419600000001 seconds
Running formula algorithm 1000000 times for 100000000 took 0.274908403 seconds
Running generator algorithm 1000000 times for 1000000000 took 0.10683704200000001 seconds
Running formula algorithm 1000000 times for 1000000000 took 0.27524084800000004 seconds
Running generator algorithm 1000000 times for 2000000000 took 0.13019867100000002 seconds
Running formula algorithm 1000000 times for 2000000000 took 0.274846384 seconds

简而言之,生成器算法的方法优于所有正int值的基于公式的解决方案 - 即使接近最大int值,它也快两倍以上! 基于信念的性能优化非常重要; - )

对于记录,修改上述代码以使用long变量而不是int,生成器算法变得更慢(正如预期的那样,因为它现在必须加起来long值) ,公式开始加快的转换点大约为1000000000000L,即10 12

Update2:正如IVlad和Moron所说,我不是浮点计算方面的专家:-)根据他们的建议我改进了公式:

private static boolean isFibByFormula(long num)
{
    double power = (double)num * (double)num;
    double first = 5 * power + 4;
    double second = 5 * power - 4;

    return isWholeNumber(Math.sqrt(first)) || isWholeNumber(Math.sqrt(second));
}

这将切换点降低到约。 10 8 (对于long版本 - 具有int的生成器对于所有int值仍然更快)。毫无疑问,用@Moron建议的方式替换sqrt次呼叫会进一步降低转换点。

我(和IVlad)的观点很简单,总会有一个转换点,低于该转换点,生成器算法更快。所以关于哪一个表现更好的说法一般没有任何意义,只有在上下文中。

答案 2 :(得分:6)

不是传递索引n,而是编写一个接受限制的函数,并使其生成斐波纳契数,直到并包括此限制。让它返回一个布尔值,具体取决于它是否达到或超过限制,你可以使用它来检查该值是否在序列中。

既然这是家庭作业,那么这样的推动可能就是我们应该给你的全部......

答案 3 :(得分:3)

确定。由于人们声称我只是在谈论空气(“事实”与“猜测”)而没有任何数据支持它,我写了一个我自己的基准。

不是java,而是下面的C#代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SO
{
    class Program
    {
        static void Main(string[] args)
        {
            AssertIsFibSqrt(100000000);

            MeasureSequential(1);
            MeasureSqrt(1);

            MeasureSequential(10);
            MeasureSqrt(10);

            MeasureSequential(50);
            MeasureSqrt(50);

            MeasureSequential(100);
            MeasureSqrt(100);


            MeasureSequential(100000);
            MeasureSqrt(100000);

            MeasureSequential(100000000);
            MeasureSqrt(100000000);

        }

        static void MeasureSequential(long n)
        {
            int count = 1000000;
            DateTime start = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                IsFibSequential(n);
            }
            DateTime end = DateTime.Now;

            TimeSpan duration = end - start;

            Console.WriteLine("Sequential for input = " + n + 
                              " : " + duration.Ticks);
        }

        static void MeasureSqrt(long n)
        {
            int count = 1000000;

            DateTime start = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                IsFibSqrt(n);
            }
            DateTime end = DateTime.Now;

            TimeSpan duration = end - start;

            Console.WriteLine("Sqrt for input =  " + n + 
                              " : " + duration.Ticks);
        }

        static void AssertIsFibSqrt(long x)
        {

            Dictionary<long, bool> fibs = new Dictionary<long, bool>();
            long a = 0;
            long b = 1;
            long f = 1;

            while (b < x)
            {
                f = a + b;
                a = b;
                b = f;

                fibs[a] = true;
                fibs[b] = true;
            }

            for (long i = 1; i <= x; i++)
            {
                bool isFib = fibs.ContainsKey(i);

                if (isFib && IsFibSqrt(i))
                {
                    continue;
                }

                if (!isFib && !IsFibSqrt(i))
                {
                    continue;
                }

                Console.WriteLine("Sqrt Fib test failed for: " + i);
            }
        }
        static bool IsFibSequential(long x)
        {
            long a = 0;
            long b = 1;
            long f = 1;

            while (b < x)
            {
                f = a + b;
                a = b;
                b = f;
            }
            return x == f;
        }

        static bool IsFibSqrt(long x)
        {
            long y = 5 * x * x + 4;

            double doubleS = Math.Sqrt(y);

            long s = (long)doubleS;

            long sqr = s*s;

            return (sqr == y || sqr == (y-8));
        }
    }
}

这是输出

Sequential for input = 1 : 110011
Sqrt for input =  1 : 670067

Sequential for input = 10 : 560056
Sqrt for input =  10 : 540054

Sequential for input = 50 : 610061
Sqrt for input =  50 : 540054

Sequential for input = 100 : 730073
Sqrt for input =  100 : 540054

Sequential for input = 100000 : 1490149
Sqrt for input =  100000 : 540054

Sequential for input = 100000000 : 2180218
Sqrt for input =  100000000 : 540054

当n = 50本身时,sqrt方法胜过朴素方法,可能是由于我的机器上存在硬件支持。即使它是10 ^ 8(就像在彼得的测试中一样),在该截止值下最多有40个斐波那契数字,这可以很容易地放在查找表中,并且仍然可以为较小的值击败天真版本。

此外,Peter对SqrtVersion的执行情况很糟糕。他并不需要使用Math.Pow计算两个平方根或计算能力。在发布他的基准测试结果之前,他至少可以尝试做得更好。

无论如何,我会让这些事实说明一切,而不是所谓的'猜测'。

答案 4 :(得分:2)

当且仅当5x ^ 2 + 4和5x ^ 2 - 4中的一个是完美正方形时,正整数x是斐波纳契数

答案 5 :(得分:2)

有许多方法可用于确定给定数字是否在斐波那契序列中,其中的一个选项可以在wikipedia上看到。

鉴于你已经完成的工作,我可能会采用更强力的方法,例如:

  1. 生成斐波纳契数
  2. 如果小于目标数,则生成下一个斐波纳契并重复
  3. 如果是目标号码,那么成功
  4. 如果它大于目标数,则失败。
  5. 我可能会使用递归方法,传入当前的n值(即计算第n个斐波纳契数),以及目标数。

答案 6 :(得分:2)

//Program begins


public class isANumberFibonacci {

    public static int fibonacci(int seriesLength) {
        if (seriesLength == 1 || seriesLength == 2) {
            return 1;
        } else {
            return fibonacci(seriesLength - 1) + fibonacci(seriesLength - 2);
        }
    }

    public static void main(String args[]) {
        int number = 4101;
        int i = 1;
        while (i > 0) {
            int fibnumber = fibonacci(i);
            if (fibnumber != number) {
                if (fibnumber > number) {
                    System.out.println("Not fib");
                    break;
                } else {
                    i++;
                }
            } else {
                System.out.println("The number is fibonacci");
                break;
            }
        }
    }
}

//Program ends

答案 7 :(得分:1)

如果我的Java不太生锈......

static bool isFib(int x) {
    int a=0;
    int b=1;
    int f=1;
    while (b < x){
        f = a + b;
        a = b;
        b = f;
    }
    return x == f;
}

答案 8 :(得分:1)

尝试利用您已编写的代码,我首先提出以下建议,因为这是最简单的解决方案(但效率最高):

private static void main(string[] args)
{
    //This will determnine which numbers between 1 & 100 are in the fibonacci series
    //you can swop in code to read from console rather than 'i' being used from the for loop
    for (int i = 0; i < 100; i++)
    {
        bool result = isFib(1);

        if (result)
            System.out.println(i + " is in the Fib series.");

        System.out.println(result);
    }

}

private static bool isFib(int num)
{
    int counter = 0;

    while (true)
    {
        if (fib(counter) < num)
        {
            counter++;
            continue;
        }

        if (fib(counter) == num)
        {
            return true;
        }

        if (fib(counter) > num)
        {
            return false;
        }
    }
}

我会提出一个更优雅的解决方案来生成斐波纳契数,它可以像这样利用递归:

public static long fib(int n) 
{
   if (n <= 1) 
      return n;
   else 
      return fib(n-1) + fib(n-2);
}

阅读额外的赠送金额: http://en.wikipedia.org/wiki/Fibonacci_number#Recognizing_Fibonacci_numbers

你会看到有一些更有效的方法来测试一个数字是否在Fibonacci 系列中,即:(5z ^ 2 + 4或5z ^ 2 - 4)=完美方。

//(5z^2 + 4 or 5z^2 − 4) = a perfect square 
//perfect square = an integer that is the square of an integer
private static bool isFib(int num)
{
    double first = 5 * Math.pow((num), 2) + 4;
    double second = 5 * Math.pow((num), 2) - 4;

    return isWholeNumber(Math.sqrt(first)) || isWholeNumber(Math.sqrt(second));
}

private static bool isWholeNumber(double num)
{
    return num - Math.round(num) == 0;    
}

答案 9 :(得分:0)

我不知道是否有可以应用于用户输入的实际公式,但是,您可以生成fibonacci序列并根据用户输入进行检查,直到它变得小于生成的最后一个数字。

int userInput = n;
int a = 1, b = 1;

while (a < n) {
  if (a == n)
    return true;

  int next = a + b;
  b = a;
  a = next;
}

return false;

答案 10 :(得分:0)

你可以用两种方式做到这一点,递归和数学。 递归的方式  开始生成斐波那契序列,直到您点击数字或通过它 这里很好地描述了数学方法...... http://www.physicsforums.com/showthread.php?t=252798

祝你好运。

答案 11 :(得分:0)

考虑斐波纳契数1,1,2,3,5,8,13,21等的序列。需要构建3个堆栈,每个堆栈包含来自上述序列的数字,如下所示:

堆栈1:序列中的前10个数字。 堆栈2:序列中的前10个素数。 堆栈3:序列中的前10个非素数。

(i)给出流程图的算法 (ii)编写一个程序(BASIC,C ++或Java)来实现它。

输出:当堆栈操作发生时,你应该以任何方便的形式显示3个堆栈以及它们中保存的值。

答案 12 :(得分:0)

根据公式确定数字是否为Fibonacci:

public static boolean isNumberFromFibonacciSequence(int num){

    if (num == 0 || num == 1){
        return true;
    }

    else {
        //5n^2 - 4 OR 5n^2 + 4 should be perfect squares
        return isPerfectSquare( 5*num*num - 4) || isPerfectSquare(5*num*num - 4);
    }
}

private static boolean isPerfectSquare(int num){
        double sqrt = Math.sqrt(num);
        return sqrt * sqrt == num;
}

答案 13 :(得分:0)

认为这很简单,直到我不得不在几分钟后把头放在上面。它与产生斐波那契序列完全不同。如果是Fibonnaci,则此函数返回1,否则返回0

public static int isFibonacci (int n){
  int isFib = 0;
  int a = 0, b = 0, c = a + b; // set up the initial values
  do 
   {
    a = b;
    b = c;
    c = a + b;
    if (c == n)
    isFib = 1;
    } while (c<=n && isFin == 0)
  return isFib;
}

public static void main(String [] args){
  System.out.println(isFibonacci(89));
}
相关问题