Тест, если число Фибоначчи
Я знаю, как составить список чисел Фибоначчи, но я не знаю, как я могу проверить, принадлежит ли данное число к списку Фибоначчи - один из способов, который приходит в голову, - это создать список fib. числа до этого числа и посмотреть, если он принадлежит к массиву, но есть другой, более простой и быстрый способ.
какие идеи ?
20 ответов:
очень хороший тест, Что N является числом Фибоначчи тогда и только тогда
5 N^2 + 4
или5N^2 – 4
- это квадрат числа. Для идей о том, как эффективно проверить, что число квадратных см. и объяснение.надеюсь, что это помогает
положительное целое число, ω является числом Фибоначчи тогда и только тогда один из 5ω2 + 4 и 5ω2 - 4-это идеальный квадрат.
посмотреть Баснословные Числа Фибоначчи дополнительные.
в то время как несколько человек указывают на идеальное квадратное решение, оно включает в себя возведение в квадрат числа Фибоначчи, что часто приводит к огромные продукта.
существует менее 80 чисел Фибоначчи, которые могут даже содержаться в стандартном 64-разрядном целочисленном значении.
вот мое решение, которое работает полностью меньше чем число, которое будет проверено.
(написано на 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);
вернутся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
.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 ниже 5 млн), так как они растут экспоненциально.
Если ваши цифры не ограниченного размера, то предложенный трюк с квадратным тестированием почти наверняка будет медленнее, чем генерация последовательности Фибоначчи, пока число не будет найдено или превышено.
положительное целое число ω является числом Фибоначчи
, если и только если одним из 5ω2 + 4 и 5ω2 - 4 является полным квадратом
С у (сказочные) числа Фибоначчи Альфреда Posamentier и Ингмар Леманн
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); }
OMG есть только четыре!!!
С другим методом
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
- Это целое число, вы будете иметь свой ответ.Edit как указывает @psmears, та же статья в Википедии также есть раздел по обнаружению чисел Фибоначчи. Википедия является отличным источником.
смотрите раздел "распознавание чисел Фибоначчи" на статья Википедии о числах Фибоначчи.
Так как числа Фибоначчи растут экспоненциально, метод, который вы предлагаете, довольно быстрый. Другой - это этой.
из Википедии:http://en.wikipedia.org/wiki/Fibonacci_number
положительное целое число z является Фибоначчи число тогда и только тогда, когда один из 5z^2 + 4 или 5z^2-4-это идеальный квадрат.
основываясь на более ранних ответах меня и 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 номеров легко доступен в интернете.
но этот код описывает работоспособный алгоритм, при условии, что у вас достаточно точности, и не переполняет вашу систему представления чисел.
re: код Ахмада-более простой подход без рекурсии или указателей, довольно наивный, но не требует почти никакой вычислительной мощности для чего-либо, кроме действительно титанических чисел (примерно 2n дополнений для проверки N-го числа fib, которое на современной машине займет миллисекунды в худшем случае)
/ / возвращает pos, если он что-то находит, 0, если это не так (C/C++ обрабатывает любое значение !=0 как истина, так же конечный результат)
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+корень(5))/2] SUP и Н+1 - [(1-корень(5))/2] с SUP П+1 ]/ корень(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% быстрее. Как указывает абеленки, это компромисс между тем, есть ли у вас место для возведения в квадрат битовых чисел.
конечно, самый быстрый способ-это окрошка Все числа Фибоначчи в доменном пространстве. Вдоль линий другой момент, что абеленки делает, есть только 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-решение может быть сделано, как показано ниже. Но все же его можно оптимизировать
следующее решение работает для
- 1≤T≤10 ^5
- 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; } }
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; }
будет ли это работать?