关于c ++:测试一个数字是否是斐波纳契数

Test if a number is fibonacci

我知道如何列出斐波那契数列表,但我不知道如何测试给定的数字是否属于斐波那契数列表——我想到的一种方法是生成斐波那契数列表。数到这个数字,看看它是否属于数组,但必须有另一种更简单、更快的方法。

有什么想法吗?


一个非常好的测试是,如果且仅当5 N^2 + 45N^2 – 4是平方数时,n是斐波那契数。关于如何有效地测试一个数是平方的,请参考SO讨论。

希望这有帮助


当且仅当5ω2+4和5ω2-4中的一个是完全平方时,正整数ω是斐波那契数。

更多信息请参见斐波那契数列。

alt text


虽然有几个人指出了完美的平方解,但它涉及平方斐波那契数,通常会产生大量的乘积。

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

这是我的解决方案,它的操作完全小于要测试的数字。(用C_书写,使用基本类型,如doublelong。但是对于更大的类型,该算法应该可以很好地工作。)

1
2
3
4
5
6
7
8
9
10
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是顺序中的第四个数字:IsFib(3, out idx);将返回true,值为4。8是顺序中的第6个数字:IsFib(8, out idx);将返回true,值为6。13是第7个数字;IsFib(13, out idx);将返回true,值为7

一个例外是IsFib(1, out idx);,它将返回2,尽管值1同时出现在索引1和2上。

如果IsFib通过非fibonacci数,则返回falseidx的值将是小于T的最大fibonacci数的指数。

16不是斐波那契值,IsFib(16, out idx);返回false7值。您可以使用binet公式将索引7转换为fibonacci值13,这是小于16的最大数字。


1
2
3
4
5
6
7
8
#!/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


如果你的数字是有界的,那么把所有低于上限的斐波那契数字放入哈希表,测试包含性就可以了。很少有斐波那契数(例如,只有38个低于5毫米),因为它们呈指数增长。

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


正整数ω是斐波那契数

If and only if one of
5ω2 + 4 and 5ω2
- 4 is a perfect square

来自阿尔弗雷德·波萨门蒂埃和英格玛·莱曼的(难以置信的)斐波纳契数

1
2
3
4
5
6
7
8
9
10
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) ;
}

我从这个来源复制的

1k10k之间打印斐波那契数的代码段。

1
2
3
4
5
for (int i = 1000; i < 10000; i++)
{
         if (isFibonacci(i))
              Console.Write(""+i);
}

天哪,只有四个!!!!

用其他方法

1
2
3
4
5
6
7
8
9
10
11
12
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)]


对于一个解决方案,看看比奈的公式。(在维基百科的斐波那契数列下查找"闭式表达式")。

它说斐波那契数列是由一个简单的闭式公式产生的:

alt text

我相信如果你解出n,并测试n是否是整数,你会得到你的答案。

正如@psmears指出的那样,同样的维基百科文章也有一个关于检测斐波那契数的章节。维基百科是一个很好的来源。


参见维基百科关于斐波那契数的文章中的"识别斐波那契数"一节。


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


根据我之前的回答和PSMEARS,我编写了这个C代码。

它缓慢地完成这些步骤,并且可以明显地减少和优化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 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个斐波那契数无效。

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

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

前300个数字的列表在网上很容易找到。

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


回复:艾哈迈德的代码——一种简单的方法,没有递归或指针,相当简单,但是除了真正的泰坦尼克号以外,几乎不需要计算能力(大约增加2n个来验证第n个fib号,在现代机器上,最坏情况下需要数毫秒)。

//返回POS,如果它发现任何东西,0如果它不(C/C++)处理任何值!=0为真,所以最终结果相同)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;

}


来自维基百科:http://en.wikipedia.org/wiki/fibonacci_number

A positive integer z is a Fibonacci
number if and only if one of 5z^2 + 4
or 5z^2 ? 4 is a perfect square.


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

如果k是待测对数(k*2.2336),则对数(1.618)应为整数!

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

通过将最接近的整数取为回答并替换为(*)以确认结果为k。


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

以下解决方案适用于

  • 1±t=10 ^ 5
  • 1±n小于10 ^ 10
  • t是测试用例的数量,n是数字的范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
        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;
            }
        }


    我在这里介绍的方法上运行了一些基准测试,以及简单的加法、预计算数组以及将结果记在哈希表中。对于Perl,至少平方法比对数法快一点,可能快20%。正如Abbelenky指出的,在是否有平方位数字的空间之间进行权衡。

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

    您应该预先计算它们,然后将它们放入Perl哈希、Python字典或其他任何东西中。

    斐波那契数的性质非常有趣,但用它们来确定计算机程序中的某个整数是否是整数,有点像每次程序启动时编写一个子程序来计算π。


    你要处理的数字有多大?

    查找表可以为您工作吗?(可以搜索的预先计算的数字列表)

    还有一个封闭形式的表达式,我想你可以用解析的方法求出答案(尽管我不是数学家,所以我不能保证这个建议是有意义的)。


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

    1
    2
    3
    4
    5
    6
    7
    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在做什么?

    1
    2
    3
    4
    5
    6
    7
     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

    scala版本-

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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()

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #include <stdio.h>
    #include <math.h>

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

    printf("Please enter a number.
    "
    );
    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.
    "
    );
        }
    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.
    "
    );
    }
    else
    {
        printf("That number isn't in the Fibonacci sequence.
    "
    );
    }
    return 0;
    }

    这能奏效吗?