Я не думаю, что C # имеет тип данных с достаточной плавающей точностью и диапазоном, чтобы справиться с этим наивно.
Если вы действительно хотите пойти по этому пути, вы можете заметить, что конъюгат меньше единицы, поэтому делает то же самое, что и округление до ближайшего целого числа, таким образом, вы можете упростить свое решение для поиска . Затем используйте биномиальное расширение, чтобы вам нужно было только вычислить с соответствующими a и b (которые рациональны и могут быть точно вычислены с помощью BigInteger). Если вы все еще вернетесь к Double для этого, вы все равно не доберетесь намного дальше, чем 1475, но вы должны быть в состоянии выяснить, как выполнить даже эту часть только с точной целочисленной математикой ☺
Существует еще один удобный метод вычисления чисел Фибоначчи с использованием возведения в матрицу:
Это можно сделать в O (log n), если вы умны.
В итоге я реализовал их на Хаскеле. fib1
- матричное возведение в степень, а fib2
- точное целочисленное преобразование формулы в замкнутой форме, как описано выше. Их время выполнения выглядит следующим образом, как измерено Критерием при компиляции с помощью GHC 7.0.3 :
import Control.Arrow
import Data.List
import Data.Ratio
newtype Matrix2 a = Matrix2 (a, a, a, a) deriving (Show, Eq)
instance (Num a) => Num (Matrix2 a) where
Matrix2 (a, b, c, d) * Matrix2 (e, f, g, h) =
Matrix2 (a*e+b*g, a*f+b*h, c*e+d*g, c*f+d*h)
fromInteger x = let y = fromInteger x in Matrix2 (y, 0, 0, y)
fib1 n = let Matrix2 (_, x, _, _) = Matrix2 (1, 1, 1, 0) ^ n in x
binom n =
scanl (\a (b, c)-> a*b `div` c) 1 $
takeWhile ((/=) 0 . fst) $ iterate (pred *** succ) (n, 1)
evens (x:_:xs) = x : evens xs
evens xs = xs
odds (_:x:xs) = x : odds xs
odds _ = []
iterate' f x = x : (iterate' f $! f x)
powers b = iterate' (b *) 1
esqrt e n = x where
(_, x):_ = dropWhile ((<=) e . abs . uncurry (-)) $ zip trials (tail trials)
trials = iterate (\x -> (x + n / x) / 2) n
fib' n = (a, b) where
d = 2 ^ n
a = sum (zipWith (*) (odds $ binom n) (powers 5)) % d
b = sum (zipWith (*) (evens $ binom n) (powers 5)) % d
fib2 n = numerator r `div` denominator r where
(a, b) = fib' n
l = lcm (denominator a) (denominator a)
r = a + esqrt (1 % max 3 l) (b * b / 5) + 1 % 2