Test if a number is fibonacci
我知道如何列出斐波那契数列表,但我不知道如何测试给定的数字是否属于斐波那契数列表——我想到的一种方法是生成斐波那契数列表。数到这个数字,看看它是否属于数组,但必须有另一种更简单、更快的方法。
有什么想法吗?
一个非常好的测试是,如果且仅当
希望这有帮助
当且仅当5ω2+4和5ω2-4中的一个是完全平方时,正整数ω是斐波那契数。
更多信息请参见斐波那契数列。
虽然有几个人指出了完美的平方解,但它涉及平方斐波那契数,通常会产生大量的乘积。
有少于80个斐波那契数,甚至可以保存在一个标准的64位整数中。
这是我的解决方案,它的操作完全小于要测试的数字。(用C_书写,使用基本类型,如
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年多之后,一位评论者询问了由
参数2是斐波那契序列的"索引"。如果要测试的值,
斐波那契序列是
一个例外是
如果
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) ; } |
我从这个来源复制的
在
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)] |
对于一个解决方案,看看比奈的公式。(在维基百科的斐波那契数列下查找"闭式表达式")。
它说斐波那契数列是由一个简单的闭式公式产生的:
我相信如果你解出
正如@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解决方案可以如下完成。但仍然可以优化
以下解决方案适用于
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; } |
这能奏效吗?