测试数字是否为斐波那契


73

我知道如何制作斐波那契数字列表,但我不知道如何测试给定数字是否属于斐波那契列表-一种想到的方法是生成fib列表。直到该数字为止,并查看它是否属于数组,但是必须有另一个更简单,更快速的方法。

有任何想法吗 ?


6
对我来说看起来像是作业,所以我添加了作业标签。
Gerco Dries 2010年

1
有关相关问题,请参见stackoverflow.com/questions/1525521/…
mtrw

5
请允许OP自己添加作业标签(随时要求澄清)。很多事情看起来好像不是家庭作业。
danben 2010年

6
请不要仅仅因为它“看起来合适”而添加标签。它“看起来像我”,就像OP想要在Brainf * ck中做到这一点一样,我应该添加该标签吗?
IVlad

Answers:


92

一个很好的测试是,当且仅当5 N^2 + 4或是5N^2 – 4平方数时,N是斐波那契数。有关如何有效测试数字是否为平方的想法,请参阅SO讨论

希望这可以帮助


2
+1是因为说“或”比说“ +”和“ and”更清晰第4次,我阅读了其他答案,我以为他们说的是不同的话,因为我没有看到“ one of”部分
Davy8

2
我对此解决方案表示怀疑,因为它涉及对斐波那契数进行平方。斐波那契数增长非常迅速,并且大多数都非常大。平方不是在计算上变得昂贵吗?
abelenky

是的,超过2 ^ 63(类似于Fib(300)),您将不得不使用一些任意精度的算术,这将非常昂贵。随着数字的增长,您必须使用Binet公式或其他方法求近似方法。我会惊讶地发现任何适用于大量数字的有效精确方法!
Il-Bhima 2010年

2
嗯...如果正好需要满足命题A和B中的一个(但不能同时包含两个!),则不能写“ A或B”,因为如果A为true,则B为false,如果A为B,则此复合语句为true false和B为true,以及A和B均为true。然后,您需要显式地编写“恰好之一”,或使用逻辑“ xor”运算符而不是“ or”。
Andreas Rejbrand

2
但是似乎“或”确实是正确的运算符。看到这一点,设定N = 1。然后,N为Fibonacci数,和两个5 * N ^ 2 + 4和5 * N ^ 2 - 4是完美的正方形。如果我们有一个xor运算符,那么即使1是斐波那契数,“ A xor B”也将是错误的,并且存在矛盾。(在这里我认为该定理对“或”或“异或”是正确的。)
Andreas Rejbrand 2010年

50

一个正整数,ω是一个Fibonacci数,当且如果任5ω只有2 + 4或5ω 2 -图4是一个完全平方。

有关更多信息,请参见神话般的斐波那契数

替代文字


34

虽然有几个人指出了完美平方解决方案,但它涉及对斐波那契数进行平方运算,从而经常产生大量产品。

甚至可以以标准的64位整数保存少于80个斐波那契数。

这是我的解决方案,它的运行完全小于要测试的数量。
(用C#编写,使用诸如double和的基本类型long。但是该算法应该适用于较大的类型。)

static bool IsFib(long T, out long idx)
{
    double root5 = Math.Sqrt(5);
    double phi = (1 + root5) / 2;

    idx    = (long)Math.Floor( Math.Log(T*root5) / Math.Log(phi) + 0.5 );
    long u = (long)Math.Floor( Math.Pow(phi, idx)/root5 + 0.5);

    return (u == T);
}


在我写完此答案的4年后,一个评论者询问了由传递的第二个参数out

参数#2是斐波纳契数列的“索引”。
如果要测试的值T是斐波那契数,那么idx它将是斐波那契数列中该数字从1开始的索引。(一个值得注意的例外)

斐波那契数列是1 1 2 3 5 8 13,等等
。3是数列中的第4个数字:IsFib(3, out idx);returntrue和value 4
8是序列中的第六个数字:IsFib(8, out idx);将返回true和value 6
13是第七个数字;IsFib(13, out idx);将返回true并有价值7

一个例外是IsFib(1, out idx);2即使值1出现在索引1和2上,也会返回。

如果IsFib传递了非斐波那契数,它将返回false,其值idx将是小于的最大斐波那契数的索引T

16不是斐波那契值。
IsFib(16, out idx);将返回false并有价值7
您可以使用Binet公式将索引7转换为斐波那契值13,该值是小于16的最大数。


10
简洁的实现。我实际上在比赛中使用了此功能:hackerrank.com/contests/codesprint5/challenges/is-fibo :)
Mars Robertson

谢谢。看起来像魔术。@Michal我也在hackerrank竞赛中使用了此功能。
kushdilip 2014年

非常好-谢谢!我用它来获取最接近的斐波那契数:)但是在现实生活中,我认为不需要计算这些数,而是将它们存储在数据库中(就像您在其他文章中所建议的那样)
Prokurors

1
只是一个问题,第二个参数到底是什么?为什么要通过引用传递它?
全能骆驼Moha 2014年

1
出于好奇,您是怎么想到这个的?
user3450695 2014年

21
#!/bin/bash
victim="144"
curl http://aux.planetmath.org/files/objects/7680/fib.txt | sed 's/^[0-9]*//;s/[ \t]//g' | grep "^$victim$" >/dev/null 2>/dev/null
if [[ $? -eq 0 ]] ; then
    echo "$victim is a fibonacci number"
else
    echo "$victim aint"
fi

5
外包。爱它!
Michael Cole 2014年

12

如果您的数字是有限大小的,则可以简单地将所有斐波纳契数字放在上限之下,然后测试包含度。斐波那契数很少(例如,低于5百万的斐波那契数只有38),因为它们呈指数增长。

如果您的数字不是有界的,那么在找到或超过该数字之前,平方测试的建议技巧几乎肯定会比生成斐波那契数列慢。


11

为了寻求解决方案,请看一下Binet的配方。
(在维基百科上的斐波那契编号下查找“闭式表达式” )

它说斐波那契数的序列是由一个简单的封闭公式创建的:

替代文字

我相信,如果您求解n,并测试是否n为整数,那么您会得到答案。

编辑作为@psmears指出,同样的维基百科的文章还对检测Fibonacci数的部分。维基百科是一个很好的资源。


10

正整数ω是斐波那契数

当且仅当一个2 + 4和5ω 2 - 4是完全平方

摘自Alfred Posamentier和Ingmar Lehmann的(出色的)FIBONACCI编号

bool isFibonacci(int  w)
{
       double X1 = 5 * Math.Pow(w, 2) + 4;
       double X2 = 5 * Math.Pow(w, 2) - 4;

       long X1_sqrt = (long)Math.Sqrt(X1);
       long X2_sqrt = (long)Math.Sqrt(X2);   

       return (X1_sqrt*X1_sqrt == X1) || (X2_sqrt*X2_sqrt == X2) ;
}

我从这个来源复制了它


1k和之间打印斐波那契数的代码段10k

for (int i = 1000; i < 10000; i++)
{
         if (isFibonacci(i))
              Console.Write(" "+i);
}

天哪,只有四个

用其他方法

from math import *

phi = 1.61803399
sqrt5 = sqrt(5)

def F(n):
    return int((phi**n - (1-phi)**n) /sqrt5)

def isFibonacci(z):
    return F(int(floor(log(sqrt5*z,phi)+0.5))) == z

print [i for i in range(1000,10000) if isFibonacci(i)]

6
不需要“?true:false”部分:之前的表达式已经是布尔值。
lhf 2010年

我用python写了第二种方法,因为我不知道C#Math.Log也可以用于其他基础。你们也要我写它吗:P?大声笑
Pratik Deoghare 2010年


6

由于斐波那契数呈指数增长,因此您建议的方法非常快。另一个是这个


我真的很喜欢封闭区间的解决方案,应该比检查平方容易得多!
Matthieu M.

3

基于我和psmears的早期回答,我编写了此C#代码。

它逐步执行,可以明显地减少和优化:

// Input: T: number to test.
// Output: idx: index of the number in the Fibonacci sequence.
//    eg: idx for 8 is 6. (0, 1, 1, 2, 3, 5, 8)
// Return value: True if Fibonacci, False otherwise.
static bool IsFib(long T, out int idx)
{
    double root5 = Math.Sqrt(5);
    double PSI = (1 + root5) / 2;

    // For reference, IsFib(72723460248141) should show it is the 68th Fibonacci number

    double a;

    a = T*root5;
    a = Math.Log(a) / Math.Log(PSI);
    a += 0.5;
    a = Math.Floor(a);
    idx = (Int32)a;

    long u = (long)Math.Floor(Math.Pow(PSI, a)/root5 + 0.5);

    if (u == T)
    {
        return true;
    }
    else
    {
        idx = 0;
        return false;
    }
}

测试显示,此方法适用于前69个斐波那契数字,但分解为第70个。

F(69) = 117,669,030,460,994 - Works
F(70) = 190,392,490,709,135 - Fails

总而言之,除非您使用某种BigInt库,否则最好有一个简单的斐波那契数表查找表并进行检查,而不是运行算法。

在线提供了前300个号码的列表。

但是,如果您有足够的精度,并且不会溢出您的数字表示系统,那么这段代码确实概述了可行的算法。


phi的问题在于,使用浮点数不能完全使用它,因此您必须进行近似估算。
Rubys 2010年


2

回复:艾哈迈德(Ahmad)的代码-一种比较简单的方法,没有递归或指针,相当幼稚,但是几乎不需要任何计算能力来处理除泰坦尼克号之外的任何数字(大约2N的加法来验证Nth fib数,这在现代机器上将花费毫秒最坏的

//如果找到任何内容,则返回pos;否则,则返回0(C / C ++将任何值!= 0都视为true,因此最终结果相同)

int isFib (long n)
{
    int pos = 2;
    long last = 1;
    long current = 1;
    long temp;

    while (current < n)
    {
        temp = last;
        last = current;
        current = current + temp;
        pos++;
    }

    if (current == n)
        return pos;
    else
        return 0;

}

1
可以肯定,这是最有效的方法。
菲利普·施密特

`DEF is_fibonacci(ⅰ)A,B = 0,1,直到B> = IA,B = B,A + B返回真。如果B ==我end`结束?
斯蒂芬阮

1

斐波那契数的一般表达式是F(n)= [[((1 + sqrt(5))/ 2] sup n + 1-[(1-sqrt(5))/ 2] sup n + 1] / sqrt (5).....(*)对于大n,第二个指数变为零,并执行数值运算,我们得到F(n)= [(1.618)sup n + 1] / 2.236

如果K是要测试的数字,log(k * 2.2336)/ log(1.618)应该是整数!

例如,K等于13,我的计算器给出的答案是7.00246。K等于14时,答案是7.1564。

您可以采用最接近答案的整数并用(*)代替以确认结果为K,从而增加结果的置信度


0

您要处理的数字有多少?

查找表对您有用吗?(您可以搜索的预先计算的数字列表)

还有一个封闭形式的表达式,我想您可以反过来分析得出答案(尽管我不是数学家,所以我不能保证这个建议是有意义的)


我正在处理任意数字。如果运行非常快,那么即使是近似值也很有用。
blueberryfields,2010年

我认为psmears有解决方案:stackoverflow.com/questions/2821778/…–
阿萨夫·拉维

0

我对此处介绍的方法进行了一些基准测试,并进行了简单加法,预先计算数组并​​将结果存储在哈希中。至少对于Perl来说,平方方法比对数方法快一点,也许快20%。正如abelenky所指出的,这是在您是否有空间平方位之间的权衡。

当然,最快的方法是散列您域空间中的所有斐波那契数。按照abelenky提出的另一观点,这些吸盘中只有94个小于2 ^ 64。

您应该只对它们进行预先计算,然后将它们放入Perl哈希,Python字典等中。

斐波那契数的属性非常有趣,但是使用它们来确定计算机程序中的某个整数是否为整数,就像在编写每次程序启动时都要计算pi的子例程一样。


0

我不确定这是否是基准测试,这是我的解决方案。我希望这有帮助!

def is_fibonacci?(i)
  a,b=0,1
    until b >= i
        a,b=b,a+b
        return true if b == i
    end
end

什么A,B = B,A + B

 0, 1 = 1, 0 +1
 1, 1 = 1, 1 + 1
 1, 2 = 2, 1 + 2
 2, 3 = 3, 2 + 3

fib1 = fib2
fib2 = fib1 + fib2

0

Scala版本-

def isFib(n: Int): Boolean = {

def checkFib(f1: Int = 1, f2: Int = 1): Boolean = {

if(n == f1 || n == f2) true
else if(n < f2) false
else checkFib(f2, f1+f2)

}

checkFib()

}

0

Java解决方案可以按以下方式完成。但是仍然可以优化

以下解决方案适用于

  1. 1≤T≤10^ 5
  2. 1≤N≤10^ 10

T是测试用例的数量,N是数量范围

    import java.util.Scanner;
    import java.math.BigDecimal;
    import java.math.RoundingMode;

    public class FibonacciTester {
        private static BigDecimal zero = BigDecimal.valueOf(0);
        private static BigDecimal one = BigDecimal.valueOf(1);
        private static BigDecimal two = BigDecimal.valueOf(2);
        private static BigDecimal four = BigDecimal.valueOf(4);
        private static BigDecimal five = BigDecimal.valueOf(5);

        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            BigDecimal[] inputs = new BigDecimal[n];
            for (int i = 0; i < n; i++) {
                inputs[i] = sc.nextBigDecimal();
            }

            for (int i = 0; i < inputs.length; i++) {
                if (isFibonacci(inputs[i]))
                    System.out.println("IsFibo");
                else
                    System.out.println("IsNotFibo");
            }


        }

        public static boolean isFibonacci(BigDecimal num) {
            if (num.compareTo(zero) <= 0) {
                return false;
            }

            BigDecimal base = num.multiply(num).multiply(five);
            BigDecimal possibility1 = base.add(four);
            BigDecimal possibility2 = base.subtract(four);


            return (isPerfectSquare(possibility1) || isPerfectSquare(possibility2));
        }

        public static boolean isPerfectSquare(BigDecimal num) {
            BigDecimal squareRoot = one;
            BigDecimal square = one;
            BigDecimal i = one;
            BigDecimal newSquareRoot;
            int comparison = -1;

            while (comparison != 0) {
                if (comparison < 0) {
                    i = i.multiply(two);
                    newSquareRoot = squareRoot.add(i).setScale(0, RoundingMode.HALF_UP);
                } else {
                    i = i.divide(two);
                    newSquareRoot = squareRoot.subtract(i).setScale(0, RoundingMode.HALF_UP);
                }

                if (newSquareRoot.compareTo(squareRoot) == 0) {
                    return false;
                }

                squareRoot = newSquareRoot;
                square = squareRoot.multiply(squareRoot);
                comparison = square.compareTo(num);
            }

            return true;
        }
    }

-1
int isfib(int n /* number */, int &pos /* position */)
{
   if (n == 1)
   {
      pos=2;  // 1 1
      return 1;
   }
   else if (n == 2)
   {
      pos=3;  // 1 1 2
      return 1;
   }
   else
   {
      int m = n /2;
      int p, q, x, y;
      int t1=0, t2 =0;
      for (int i = m; i < n; i++)
      {
        p = i;
        q = n -p;    // p + q = n
        t1 = isfib(p, x);
        if (t1) t2 = isfib(q, y);
        if (t1 && t2 && x == y +1)
        {
           pos = x+1;
           return 1; //true
        }
      }
      pos = -1;
      return 0; //false
   }
}

这个怎么样?


1
好的逻辑,但几乎完全不可读。必须从事变量命名的工作
-Phillip Schmidt,

-1
#include <stdio.h>
#include <math.h>

int main()
{
int number_entered, x, y;

printf("Please enter a number.\n");
scanf("%d", &number_entered);
x = y = 5 * number_entered^2 + 4;        /*Test if 5N^2 + 4 is a square number.*/
x = sqrt(x);
x = x^2;
if (x == y)
{
        printf("That number is in the Fibonacci sequence.\n");
    }
x = y = 5 * number_entered^2 - 4;        /*Test if 5N^2 - 4 is a square number.*/
x = sqrt(x);
x = x^2;
if (x == y)
{
    printf("That number is in the Fibonacci sequence.\n");
}
else
{
    printf("That number isn't in the Fibonacci sequence.\n");
}
return 0;
}

这样行吗?


1
在C中,^按位XOR运算符。您需要x * xpow(x,2)平方一个数字。程序逻辑中也存在问题。
QuasarDonkey 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.