44

Problem #25 from Project Euler asks:

What is the first term in the Fibonacci sequence to contain 1000 digits?

The brute force way of solving this is by simply telling the computer to generate Fibonacci numbers until it finds the first one that has 1000 digits. I wanted to look for a more mathematical solution that doesn't require that many computations.

Initially, I expected that by plotting the Fibonacci numbers (mapping the number itself to the number of digits) I would get a logarithmic graph. I only plotted the first few ones and the sequence looked more like it had linear progression (I hope that's the correct mathematical term; I mean similar to $y=x$ functions.)

I also noticed that, roughly, every five numbers the number of digits is increased by 1 — except the four digit numbers (there's only four of them) and the one digits numbers (if you count the first 1, there's six of them).

$$1, 1, 2, 3, 5, 8$$ $$13, 21, 34, 55, 89$$ $$144, 233, 377, 610, 987$$ $$1597, 2584, 4181, 6765$$ $$10946, ...$$

Thus, the first number with seven digits would be $n = 5 \cdot (7 - 1)$, which turned out to be correct. However, starting with the tenth digit, the behavior of the sequence changes (or rather, it becomes clear that it's not linear). The first number with 10 digits is not $5 \cdot (10 -1)$, but $5 \cdot (10 - 1) - 1$.

Plotting the sequence for even larger numbers (again, numbers mapped to their digit count), you get a very slight logarithmic curve. For example, the first number with 1000 digits is $5 \cdot (1000 - 43)$ (WolframAlpha).

My question is,
How can the Fibonacci sequence's behavior be abstracted such that the problem can be solved more elegantly, as opposed to using the brute force algorithm.


Edit: Regarding efficiency

The question, I asked mainly to satisfy my curiosity. Doing this by brute-force is probably the best way in a real world application (computers can do it fast and the code is clearer). But (again, just for entertainment) the more efficient solution can still be to use a mathematical formula to find the index of the number you're looking for; here's why:

  1. Conditionals are expensive. Doing fewer of them is always good, and the brute-force approach requires you to do a check on every number you generate.
  2. Some languages (like C++ and D) allow you to do tricks like generating part of the Fibonacci sequence at compile-time (see meta-programming). This means less work at run-time, though admittedly, this could also apply to the brute-force approach.

Not doing checks on the numbers, as well as generating many of them at compile time, can significantly make the algorithm faster (but only in a theoretical sense; most computers nowadays are fast enough that no human will ever notice the difference unless you do the computations a couple of times a second).

Besides, the process of counting the digits of a numbers — required by the brute-force approach — is itself pretty expensive, whether you use the $\lceil\log_{10}n \rceil$ algorithm or the $n\mod10$ algorithm.

Paul Manta
  • 3,405
  • 4
  • 33
  • 48
  • 15
    (+1) "This question shows research effort; it is useful and clear" Check. Check. Check. – The Chaz 2.0 Sep 04 '11 at 15:58
  • See also http://math.stackexchange.com/questions/9026. – Mike Spivey Sep 06 '11 at 03:23
  • Why are you using the log or mod to check the number of digits? It's probably a lot faster to check if the number is greater than 10^1000. Subtracting and checking if the result is negative is surely a lot faster than taking the log or the modulo of a 1000 digit number. – Hannesh Sep 06 '11 at 10:24
  • @Hannesh I know, but I was talking about a more general algorithm that counts the digits, not one that checks whether a number is within a certain range. – Paul Manta Sep 06 '11 at 10:30

7 Answers7

12

The sequence $n \mapsto F_n$ grows exponentially. In fact, I suggest you look at this part of the wikipedia article on Fibonacci numbers, which gives exact and nearly exact formulas for $F_n$ as exponential functions. This should be very helpful in determining the smallest $n$ such that $F_n$ has $1000$ digits.

Pete L. Clark
  • 93,404
  • 10
  • 203
  • 348
  • I didn't map $n \mapsto F_n$ but rather $F_n \mapsto d(F_n)$, where $d$ is a function that gives the number of digits of a number. The second mapping is logarithmic. – Paul Manta Sep 04 '11 at 08:21
  • 2
    @Paul: sorry, you said that in your question but I missed it. Right, so $n \mapsto F_n$ is exponential and thus $n \mapsto d(F_n) \approx \log_{10} F_n$ is linear. Anyway, the point of my answer is not just that $F_n$ is exponential but is given up to the nearest integer by a very simple exponential expression, such that you can set it equal to $10^{1000}$ and solve for $n$. Does this make sense? – Pete L. Clark Sep 04 '11 at 08:28
  • 2
    Addendum to the above: when I say "solve for $n$", I mean that first you solve some equation that gives you a value of $n$ which is very nearly correct but not necessarily even an integer, and then you check nearby integers to see which one you want. I really don't want to say more than this, except that in between typing the above answer and this comment I decided to try the procedure out for myself...it works! – Pete L. Clark Sep 04 '11 at 08:41
  • Thanks, I understand what you said. :) – Paul Manta Sep 04 '11 at 08:44
  • 2
    Also note that $10^{1000}$ has $1001$ digits (I confess I missed this the first time around!) so that one might speed things up a little bit more by trying $10^{999}$ instead. But if you have access to something which will spit out values of $F_n$ for $n$ in the thousands, either way is already very fast... – Pete L. Clark Sep 04 '11 at 08:55
  • But the problem was not to find the smallest $n$ such that $F_n$ has 1000 digits -- it was to find that $F_n$ itself. – hmakholm left over Monica Sep 04 '11 at 16:02
  • @Henning: okay, but if you know the $n$ it's easy (in principle always, and even in practice given the size of $n$ in this particular case) to compute $F_n$. If you are instead given $F_n$ it's a little more trouble to recover $n$. So for someone with access to a mathematical calculating package (so for anyone with internet access, because of the existence of WolframAlpha) it seems more efficient to list $n$ as the answer rather than the $1000$ digit number $F_n$. – Pete L. Clark Sep 04 '11 at 16:06
  • 4
    @Pete, the Project Euler problems are posed as programming/algorithmic exercises -- the task is really to figure out how to produce the thing they ask for. Just asking Wolfram Alpha for the solution instead of actually solving the problem posed is not going to be any more educational than cheating on a test or bribing a teacher to pass you. It doesn't matter that _not solving the problem_ "seems more efficient" than solving it -- otherwise, what would be the point in participating at all in the first place? – hmakholm left over Monica Sep 04 '11 at 16:10
  • 1
    @Henning: okay, I take your point. I am a mathematician, not a computer scientist (and this is a math site...) so I was answering the question in that context. I agree that when I looked into the computations myself I used gp/pari, which has a built-in "fibonacci" function. Following your comment I tried using the rounded Binet's formula instead, and indeed I got not nearly enough digits of precision. – Pete L. Clark Sep 04 '11 at 16:18
  • @Henning: I don't think though that what I suggested above is comparable to cheating or bribing a teacher. The above solution uses a mathematical idea to *avoid* brute force searching, but it takes as a given that one has available an algorithm to compute $n \mapsto F_n$. If constructing that algorithm is part of the question (or, especially, if it *is* the real question), then that should be made more explicit. – Pete L. Clark Sep 04 '11 at 16:21
  • @Pete, but my point here is that brute-force searching is not appreciably harder than the "smart" solution. There's really no gain in finding the correct $n$ quickly, if _using_ that $n$ is going to be just as cumbersome as the original brute-force search would have been. That's not "avoiding" anything (except for a simple comparison in each step), it is simply a detour. Taking a given that one already has an algorithm to compute Fibonacci numbers quickly is essentially an assumption that the problem is already solved. – hmakholm left over Monica Sep 04 '11 at 16:24
  • @Henning: it really depends on the perspective. The OP said: "The brute force way of solving this is by simply telling the computer to generate Fibonacci numbers until it finds the first one that has 1000 digits. I wanted to look for more mathematical solution that doesn't require that many computations." I took this to mean: give me a solution that doesn't simply involve writing a loop that calls the Fibonacci function thousands of times. So I gave a solution that involves only calling it two or three times.... – Pete L. Clark Sep 04 '11 at 16:29
  • ...Your point that calling the function Fibonacci(n) even once likely involves the program itself calling it many times is valid, but it doesn't necessarily invalidate my solution. The OP was asking for some mathematical insight that would (from his perspective, anyway) cut down the computations necessary to do the problem, and I believe that I (and Brian, and others) gave him that. – Pete L. Clark Sep 04 '11 at 16:33
  • @Henning See my edit regarding efficiency. – Paul Manta Sep 06 '11 at 05:58
12

The $n$-th Fibonacci number is given by the following formula: $$F_n = \left\lfloor \frac{\phi^n}{\sqrt 5} + \frac12 \right\rfloor,$$ where $\displaystyle\varphi = \frac{1+\sqrt 5}{2}$. Equivalently, $F_n$ is the integer closest to $\displaystyle\frac{\varphi^n}{\sqrt 5}$. Thus, $\log_{10}F_n$ is very, very close to $\displaystyle n \log_{10}\varphi - \frac12 \log_{10}5$. Since the number of digits in the integer $m$ is $\lceil\log_{10}m \rceil$, so $-$ ignoring that very small discrepancy, which shouldn’t matter with numbers of this size $-$ you want the smallest $n$ such that $$\displaystyle n \log_{10}\varphi - \frac12 \log_{10}5 > 999.5.$$

Added: I guessed wrong about the effect of the discrepancy. By actual calculation it turns out that the value estimated from the inequality above is a little too small.

Brian M. Scott
  • 588,383
  • 52
  • 703
  • 1,170
  • I'm not quite sure why you have 999.5 rather than 1000. – Henry Sep 04 '11 at 08:48
  • @Henry: Because I wanted the ceiling of the number on the left-hand side to be at least $1000$, which means that the number itself must be more than $999.5$. – Brian M. Scott Sep 04 '11 at 09:05
  • I still do not see it. First ceilings do not work like that. Second you want the left hand side to be greater than $\log(10^{1000})$ so you do not need ceilings at this stage. Later you could have $n=\text{ceiling} \left[ \dfrac{1000 + \frac12 \log_{10}5 }{\log_{10}\varphi} \right]$. I think this works for two or more digits. – Henry Sep 04 '11 at 09:38
  • This answer (with @Henry's correction) is true as far as it goes, but does it actually help find the actual Fibonacci number asked for? Ordinary computer floating-point arithmetic is not precise enough to find all the 1000 digits of the number simply by taking a power of $\phi$, so one has to execute the exact recurrence with bignums anyway after computing how far to go -- which is just the same work as the OP's original algorithm, except for the very minor step of checking for each $F_n$ whether we've reached $10^{1000}$ or not. – hmakholm left over Monica Sep 04 '11 at 15:37
  • @Henning: The [actual question](http://projecteuler.net/index.php?section=problems&id=25) also says "The 12th term, $F_{12}$, is the first term to contain three digits" making clear that it is the index not the number which is being asked for. – Henry Sep 04 '11 at 17:45
  • @Henry, the actual task is quoted accurately in the OP's question. It plainly asks for `the first term in the Fibonacci sequence to contain 1000 digits`. It does not ask for `the index of the first term in the Fibonacci sequence to contain 1000 digits`. There is no way to misunderstand this. It wants the term with 1000 digits, not the index of the term with 1000 digits. – hmakholm left over Monica Sep 04 '11 at 21:20
  • 3
    @Henning: the format of the desired answer has been questioned several times, and the [Project Euler guidance](http://forum.projecteuler.net/viewtopic.php?f=50&t=1296) is clear. – Henry Sep 04 '11 at 22:51
7

Here is a useful fact, for any positive number n, the number of digits of n in base 10 is given by:

$$\lfloor\log_{10}(n)\rfloor + 1$$

The number of digits of the Fibonacci sequence grows linearly, as can be shown in the graph.

plot of number of digits of Fibonacci numbers

J. M. ain't a mathematician
  • 71,951
  • 6
  • 191
  • 335
Lie Ryan
  • 1,130
  • 1
  • 9
  • 16
1

The other answers giving exact forumlas for Fibonacci numbers are spot on, but if you don't have them handy, you can also solve this problem by shifting the computation to the logarithmic domain. Calculate the log, base 10, of each number, and add it to a double-precision sum; as soon as the value equals or exceeds 999 (i.e. the log, base 10, of the lowest number with 1000 digits), you've reached the right Fibonacci number.

jprete
  • 113
  • 1
  • 4
1

The answers you have got so far will help you finding the index of the first Fibonacci number greater than $10^{999}$, but are not particularly useful for finding that Fibonacci number itself, with all is 1000 digits.

For that, I think you have no choice but compute the Fibonacci sequence far enough. If you know the index in advance you can use that to decide how far to go in the computation, but that does not seem to be a significant improvement over simply checking whether each successive Fibonacci number has reached 1000 digits -- you need to compute them all anyway.

The point of the exercise must be that a naive implementation of the Fibonacci sequence (top-down, with two recursive calls in each step) is not going to complete for these sized until well after the heat death of the universe. But if you compute the sequence from the bottom up, saving all of them in an array, and simply pull the two previous numbers out of the array at each step, it's all fast and straightforward.

(You'll need an arbitrary-precision integer arithmetic library if your programming language doesn't already provide one, of course).

hmakholm left over Monica
  • 276,945
  • 22
  • 401
  • 655
  • 3
    ...or he could do a matrix exponentiation of an appropriate matrix. – J. M. ain't a mathematician Sep 04 '11 at 15:52
  • 1
    @J, yes, but will be more programming work for a dubious benefit unless he has a library that handles _both_ matrix exponentiation _and_ arbitrary-precision arithmetic in one integrated package. The straightforward iterative solution will take $O(n^2)$ time, and ought to complete in comfortably less than a minute. Under the (perhaps not completely realistic) assumption that the library has a sub-quadratic multiplication algorithm, matrix exponentiation by squaring would get down to about $O(n\log^2(n))$, but it seems not to be worth the trouble. – hmakholm left over Monica Sep 04 '11 at 15:58
  • @J.M. Maybe we should have a tag for [Fibonacci matrix] ! $$$$ :) – The Chaz 2.0 Sep 04 '11 at 15:59
  • 1
    The problem cited asks for the index, not the term itself. – Ross Millikan Sep 04 '11 at 19:22
  • @Ross, the OP quotes the problem correctly. It asks for the _first term_ of the appropriate size, not for the _index of the first term_. – hmakholm left over Monica Sep 04 '11 at 21:15
  • 2
    @Henning Makholm: You are right that the quote is accurate, but the answer it accepted from me was the term number. The answer box won't hold 1000 digits (many problems ask for the last 8 digits of a big number). I believe there was discussion on the forum suggesting rewording, but it hasn't happened. – Ross Millikan Sep 04 '11 at 21:26
  • Well, the fact that they are checking for an answer to a different question than the one they are asking does not make the question actually asked into a different one. – hmakholm left over Monica Sep 04 '11 at 21:37
  • 1
    The matrix exponentiation gives the insight needed to produce a simple and efficient recursive evaluation method. http://www.cheddarmonk.org/Fibonacci.html – Peter Taylor Sep 06 '11 at 08:48
  • @Peter is on the right track. I think that a very efficient approach is to first find the index using the approximation method, and then do matrix exponentiation with the square and multiply algorithm (or some such). That we only need to do $O(\log_2n)$ matrix multiplications to compute the required $F_n$. If they accept the last 8 digits as an answer (admittedly the question posed here was different:-), then it suffices to do the matrix powers mod $10^8$ meaning that 64-bit integers would suffice. – Jyrki Lahtonen Sep 06 '11 at 09:09
0

The brute force method IS the elegant method. Compare the gyrations and convolutions above to: find each Fibonnaci number in sequence, count the number of digits, stop at the first one with 1,000 digits (if any).

Patrick
  • 11
  • 1
    You're right, that method is much better than it looks at first glance. – Charles Sep 04 '11 at 16:40
  • "If any"? Since $F_{n+1}$ is extremely close to $((1+\sqrt{5})/2) \cdot F_n$, it is clear that except for very small $d$ (in fact $d \geq 2$ suffices) there are either $4$ or $5$ Fibonacci numbers with $d$ digits. Maybe the gyrations are not so bad after all? – Pete L. Clark Sep 04 '11 at 16:45
  • Patrick: would you make the same statement in (say) 1950? I don't think brute force is at all elegant; it's just convenient and simple in a time where we have easy access to cheap powerful computing resources. – Fixee Sep 04 '11 at 17:02
  • 1
    @Fixee, even in 1950, if you were asked to compute the first Fibonacci number that had 1000 digits, that's what you had to do. Knowing the index of that number in the sequence is actually not going to simplify the computations for you. – hmakholm left over Monica Sep 04 '11 at 21:31
  • @Henning I asked the question to satisfy my curiosity, because brute force is completely uninteresting. :) Even so, for very large numbers the non-brute-force approach may be faster. Brute force implies doing a check on every number you generate, and [conditionals are expensive](http://stackoverflow.com/questions/315306#315382). It might (theoretically) be better to know ahead of time how many numbers you have to generate, so you don't have to do any more checks. – Paul Manta Sep 06 '11 at 05:36
0

Violating both the terms of the question and good taste, I spent 1.5 minutes and wrote a program to solve this. Being a computer scientist, it was an irresistible temptation.

Python seems the logical choice for something quick: it has arbitrary precision integers built in.

Solution deleted due to comment below

Fixee
  • 11,199
  • 6
  • 39
  • 64
  • In python, `t = j; j += i; i = t` can be written as `i, j = j+i, i`. Also, rather than calculate the log of j in every loop, I thought it would be quicker to just see if it's greater than or equal to `10 ** 999`, but in tests, it made only a small difference. – rjmunro Sep 04 '11 at 23:34
  • @rjmunro: I had written `i,j = j,j+1` originally, but changed it before posting here, hoping to avoid too much python-specific syntax so that C programmers would understand the code. (Btw, I don't think the two code snippets in your comment are equivalent.) Also, you're right that `10 **999` is probably a bit faster than a `log`, however that depends on how exponentiation is computed in python... it might be just as bad. I usually don't try optimizing in Python much; the language is horrendously slow (even jitted), so I'd never use for anything where I care about performance. – Fixee Sep 05 '11 at 00:15
  • It's not that 10**999 is *faster* than log(), it's that you only have to compute it once at the start. You are computing `log(j)` on every loop. – rjmunro Sep 05 '11 at 11:21
  • @rjmunro: Yup true. So inside the loop, we have to ask if it's faster to compute the log of a huge number or to compare one huge number to another. I'd have to think that the latter is much faster, as you suggested. (Though once again, I think talking about optimized Python is akin to talking about high-performance tricycles.) – Fixee Sep 05 '11 at 16:46
  • 1
    I can understand the temptation to solve the problem (I gave into that myself) but not the temptation to post the solution here, contrary to the instructions at Project Euler. Haven't you just spoiled the puzzle for a lot of (presumably young, non-professional computer scientist) people? – Pete L. Clark Sep 05 '11 at 21:19
  • @Pete L. Clark: I am not at all familiar with Project Euler. I just had a look; can you direct me to the instructions you reference in your comment? Also, I have removed my solution in light of your comment. – Fixee Sep 06 '11 at 01:51
  • @Fixee: thanks for removing the exact answer part of your answer. I'm not terribly familiar with PE either, but you can get a sense of what it's about here: http://projecteuler.net/index.php?section=about. After you read this, I hope you will still agree that posting exact answers may spoil things for some people. – Pete L. Clark Sep 06 '11 at 02:58