我知道如何制作斐波那契数字列表,但我不知道如何测试给定数字是否属于斐波那契列表 - 想到的一种方法是生成 fib 列表。数到那个数字,看看它是否属于数组,但必须有另一种更简单、更快的方法。
有任何想法吗 ?
一个很好的测试是 N 是斐波那契数当且仅当5 N^2 + 4
或5N^2 – 4
是平方数。有关如何有效测试数字是否为正方形的想法,请参阅SO 讨论。
希望这可以帮助
虽然有几个人指出了完美平方解决方案,但它涉及对斐波那契数进行平方,通常会产生大量乘积。
甚至可以保存在标准 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);
}
out
.
参数#2 是斐波那契数列的“索引”。
如果要测试的值T
是斐波那契数,idx
则将是该数在斐波那契数列中的从 1 开始的索引。(有一个明显的例外)
斐波那契数列是1 1 2 3 5 8 13
,以此类推。
3 是数列中的第 4 个数字:IsFib(3, out idx);
将返回true
和 value 4
。
8 是序列中的第 6 个数字:IsFib(8, out idx);
将返回true
和 value 6
。
13 是第 7 个数字;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
。
您可以使用比内公式将索引 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
如果你的数字是有界的,那么简单地将所有低于上限的斐波那契数字放入哈希表中并测试包含将起到作用。斐波那契数很少(例如,只有 38 个低于 500 万),因为它们呈指数增长。
如果你的数字不是有界的,那么平方测试的建议技巧几乎肯定会比生成斐波那契数列要慢,直到找到或超过数字。
正整数 ω 是斐波那契数
当且仅当 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)]
对于一个解决方案,看看比内公式。(在维基百科的斐波那契数
下查找“封闭式表达式” )
它说斐波那契数列是由一个简单的封闭公式创建的:
我相信如果你解决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
总之,除非您使用某种 BigInt 库,否则最好有一个斐波那契数列的简单查找表并检查它,而不是运行算法。
前 300 个号码的列表可在线获取。
但是这段代码确实概述了一个可行的算法,只要你有足够的精度,并且不要溢出你的数字表示系统。
来自维基百科:http ://en.wikipedia.org/wiki/Fibonacci_number
正整数 z 是斐波那契数当且仅当 5z^2 + 4 或 5z^2 - 4 之一是完美正方形。
回复:艾哈迈德的代码 - 一种更简单的方法,没有递归或指针,相当幼稚,但几乎不需要计算能力来处理真正巨大的数字(大约 2N 次加法来验证第 N 个 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;
}
斐波那契数的一般表达式是 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,从而增加对结果的置信度
我对这里介绍的方法进行了一些基准测试,以及简单的加法、预计算数组并将结果存储在哈希中。至少对于 Perl,平方方法比对数方法快一点,可能快 20%。正如abelenky 指出的那样,这是在您是否有空间对位数进行平方之间进行权衡。
当然,最快的方法是对域空间中的所有斐波那契数进行散列。沿着 abelenky 提出的另一点,这些吸盘中只有 94 个小于 2^64。
您应该只预先计算它们,并将它们放入 Perl 哈希、Python 字典或其他任何东西中。
斐波那契数的属性非常有趣,但是使用它们来确定计算机程序中的某个整数是否为整数,就像在每次程序启动时编写一个子程序来计算 pi。
这是我的解决方案,我不确定它是否具有基准。我希望这有帮助!
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
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()
}
Java解决方案可以如下完成。但是还是可以优化的
以下解决方案适用于
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;
}
}
基本上所有的答案都给出了。我想添加一个非常快速的 C++ 示例代码。
基础是这里已经多次提到的查找机制。
使用比内特的公式,我们可以计算出只有极少数的斐波那契数可以适合 C++unsigned long long
数据类型,而 C++ 数据类型现在通常在 2021 年有 64 位。回旋处 93。现在这个数字非常低。
借助现代 C++ 17(及更高版本)功能,我们可以在编译时轻松地为 64 位数据类型创建std::array
所有斐波那契数。
因此,我们将只为查找数组花费 93*8= 744 BYTE的非运行时内存。
然后std::binary_search
用于查找值。因此,整个功能将是:
bool isFib(const unsigned long long numberToBeChecked) {
return std::binary_search(FIB.begin(), FIB.end(), numberToBeChecked);
}
FIB 是一个编译时间,constexpr std::array
. 那么,如何构建该数组?
我们首先将计算斐波那契数的默认方法定义为constexpr
函数:
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) noexcept {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// Calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
这样,斐波那契数可以在运行时轻松计算。std::array
然后,我们用所有斐波那契数填充 a 。我们还使用 aconstexpr
并使其成为带有可变参数包的模板。
我们使用std::integer_sequence
为索引 0、1、2、3、4、5、... 创建一个斐波那契数。
这很简单,并不复杂:
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
该函数将输入一个整数序列 0,1,2,3,4,... 并返回std::array<unsigned long long, ...>
具有相应斐波那契数的 a。
我们知道我们最多可以存储 93 个值。因此我们创建了一个下一个函数,它将使用整数序列 1,2,3,4,...,92,93 调用上述函数,如下所示:
constexpr auto generateArray() noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
而现在,终于,
constexpr auto FIB = generateArray();
将为我们提供一个名为 FIB 的编译时间std::array<unsigned long long, 93>
,其中包含所有斐波那契数。如果我们需要第 i 个斐波那契数,那么我们可以简单地写FIB[i]
. 运行时不会进行计算。
整个示例程序将如下所示:
#include <iostream>
#include <array>
#include <utility>
#include <algorithm>
#include <iomanip>
// ----------------------------------------------------------------------
// All the following will be done during compile time
// Constexpr function to calculate the nth Fibonacci number
constexpr unsigned long long getFibonacciNumber(size_t index) noexcept {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 1 };
// calculating Fibonacci value
while (index--) {
// get next value of Fibonacci sequence
unsigned long long f3 = f2 + f1;
// Move to next number
f1 = f2;
f2 = f3;
}
return f2;
}
// We will automatically build an array of Fibonacci numbers at compile time
// Generate a std::array with n elements
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};
// Max index for Fibonaccis that for an 64bit unsigned value (Binet's formula)
constexpr size_t MaxIndexFor64BitValue = 93;
// Generate the required number of elements
constexpr auto generateArray()noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
// This is an constexpr array of all Fibonacci numbers
constexpr auto FIB = generateArray();
// All the above was compile time
// ----------------------------------------------------------------------
// Check, if a number belongs to the Fibonacci series
bool isFib(const unsigned long long numberToBeChecked) {
return std::binary_search(FIB.begin(), FIB.end(), numberToBeChecked);
}
// Test
int main() {
const unsigned long long testValue{ 498454011879264ull };
std::cout << std::boolalpha << "Does '" <<testValue << "' belong to Fibonacci series? --> " << isFib(498454011879264) << '\n';
return 0;
}
使用 Microsoft Visual Studio Community 2019 版本 16.8.2 开发和测试
另外使用 gcc 10.2 和 clang 11.0.1 进行了测试
语言:C++ 17
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
}
}
这个怎么样?
#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;
}
这行得通吗?