我知道如何生成斐波那契数列,但我不知道如何检测给定数字是否属于斐波那契数列。一种方法是生成斐波那契数列直到该数字,并查看该数字是否在数组中,但肯定有另一种更简单更快的方法。
有什么想法吗?
我知道如何生成斐波那契数列,但我不知道如何检测给定数字是否属于斐波那契数列。一种方法是生成斐波那契数列直到该数字,并查看该数字是否在数组中,但肯定有另一种更简单更快的方法。
有什么想法吗?
一个非常好的测试方法是:当且仅当5 N^2 + 4
或者5N^2 – 4
为完全平方数时,N是一个斐波那契数。如果你想了解如何有效地检测一个数是否为完全平方数,请参考Stack Overflow讨论。
虽然有一些人提出了完美平方解决方案,但它涉及到对斐波那契数进行平方运算,这通常会导致一个巨大的乘积。
甚至有不到80个斐波那契数可以在标准64位整数中存储。
这是我的解决方案,它完全在比要测试的数字小的范围内操作。
(使用基本类型如double
和long
编写的C#代码。但是该算法对于更大的类型也应该可以正常工作。)
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);
}
out
传递。T
是斐波那契数,则idx
将是该数在斐波那契数列中的基于1的索引(有一个显著的例外)。1 1 2 3 5 8 13
等。3是序列中的第4个数字: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
传递非斐波那契数,它将返回false
,并且idx
的值将是小于T
的最大斐波那契数的索引。IsFib(16, out idx);
将返回false
和值7
。您可以使用Binet's Formula将索引7转换为斐波那契值13,这是小于16的最大数字。#!/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ω2 + 4 或者 5ω2 - 4 中有一个是完全平方数。
摘自《(神奇的)斐波那契数》Alfred Posamentier 和 Ingmar Lehmann著。
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)]
timeit
模块在随机选择的1000位数上计时。基于平方的方法快了7倍。 - John Coleman针对这个问题,可以看一下比涅公式。
(在维基百科的Fibonacci Number 页面下找 "Closed-Form Expression")
它说斐波那契数列是通过一个简单的闭合公式来创建的:
我相信如果你求解n
并测试n
是否为整数,你就可以得到答案。
编辑 正如@psmears指出的,同样在维基百科上还有一个关于检测斐波那契数的部分。 维基百科是一个很好的信息来源。
根据我和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