views:

545

answers:

10

Hello,

I need to to write a Java code that checks whether the user inputed number is in the Fibonacci sequence.

I have no issue writing the Ficonacci sequence to output, but (probably because its late at night) I'm struggling to think of the sequence of "whether" it is a fibonacci number. I keep starting over and over again. Its really doing my head in.

What I currently have is the nth.

Any help would be awesome-o.

Thanks,

Emily

public static void main(String[] args)
{
    ConsoleReader console = new ConsoleReader();

    System.out.println("Enter the value for your n: ");
    int num = (console.readInt());
    System.out.println("\nThe largest nth fibonacci: "+fib(num));
    System.out.println();
}

static int fib(int n){
    int f = 0;
    int g = 1;
    int largeNum = -1;
    for(int i = 0; i < n; i++)
    {
      if(i == (n-1))
          largeNum = f;
      System.out.print(f + " ");
      f = f + g;
      g = f - g;
    }
    return largeNum;
}
+6  A: 

Instead of passing the index, n, write a function that takes a limit, and get it to generate the Fibonacci numbers up to and including this limit. Get it to return a Boolean depending on whether it hits or skips over the limit, and you can use this to check whether that value is in the sequence.

Since it's homework, a nudge like this is probably all we should be giving you...

David M
+6  A: 

If I understand correctly, what you need to do (instead of writing out the first n Fibonacci numbers) is to determine whether n is a Fibonacci number.

So you should modify your method to keep generating the Fibonacci sequence until you get a number >= n. If it equals, n is a Fibonacci number, otherwise not.

Update: bugged by @Moron's repeated claims about the formula based algorithm being superior in performance to the simple one above, I actually did a benchmark comparison - concretely between Jacopo's solution as generator algorithm and StevenH's last version as formula based algorithm. For reference, here is the exact code:

public static void main(String[] args) {
    measureExecutionTimeForGeneratorAlgorithm(1);
    measureExecutionTimeForFormulaAlgorithm(1);

    measureExecutionTimeForGeneratorAlgorithm(10);
    measureExecutionTimeForFormulaAlgorithm(10);

    measureExecutionTimeForGeneratorAlgorithm(100);
    measureExecutionTimeForFormulaAlgorithm(100);

    measureExecutionTimeForGeneratorAlgorithm(1000);
    measureExecutionTimeForFormulaAlgorithm(1000);

    measureExecutionTimeForGeneratorAlgorithm(10000);
    measureExecutionTimeForFormulaAlgorithm(10000);

    measureExecutionTimeForGeneratorAlgorithm(100000);
    measureExecutionTimeForFormulaAlgorithm(100000);

    measureExecutionTimeForGeneratorAlgorithm(1000000);
    measureExecutionTimeForFormulaAlgorithm(1000000);

    measureExecutionTimeForGeneratorAlgorithm(10000000);
    measureExecutionTimeForFormulaAlgorithm(10000000);

    measureExecutionTimeForGeneratorAlgorithm(100000000);
    measureExecutionTimeForFormulaAlgorithm(100000000);

    measureExecutionTimeForGeneratorAlgorithm(1000000000);
    measureExecutionTimeForFormulaAlgorithm(1000000000);

    measureExecutionTimeForGeneratorAlgorithm(2000000000);
    measureExecutionTimeForFormulaAlgorithm(2000000000);
}

static void measureExecutionTimeForGeneratorAlgorithm(int x) {
    final int count = 1000000;
    final long start = System.nanoTime();
    for (int i = 0; i < count; i++) {
        isFibByGeneration(x);
    }
    final double elapsedTimeInSec = (System.nanoTime() - start) * 1.0e-9;
    System.out.println("Running generator algorithm " + count + " times for " + x + " took " +elapsedTimeInSec + " seconds");
}

static void measureExecutionTimeForFormulaAlgorithm(int x) {
    final int count = 1000000;
    final long start = System.nanoTime();
    for (int i = 0; i < count; i++) {
        isFibByFormula(x);
    }
    final double elapsedTimeInSec = (System.nanoTime() - start) * 1.0e-9;
    System.out.println("Running formula algorithm " + count + " times for " + x + " took " +elapsedTimeInSec + " seconds");
}

static boolean isFibByGeneration(int x) {
    int a=0;
    int b=1;
    int f=1;
    while (b < x){
        f = a + b;
        a = b;
        b = f;
    }
    return x == f;
}

private static boolean isFibByFormula(int num) {
    double first = 5 * Math.pow((num), 2) + 4;
    double second = 5 * Math.pow((num), 2) - 4;

    return isWholeNumber(Math.sqrt(first)) || isWholeNumber(Math.sqrt(second));
}

private static boolean isWholeNumber(double num) {
    return num - Math.round(num) == 0;
}

The results surprised even me:

Running generator algorithm 1000000 times for 1 took 0.007173537000000001 seconds
Running formula algorithm 1000000 times for 1 took 0.223365539 seconds
Running generator algorithm 1000000 times for 10 took 0.017330694 seconds
Running formula algorithm 1000000 times for 10 took 0.279445852 seconds
Running generator algorithm 1000000 times for 100 took 0.030283179 seconds
Running formula algorithm 1000000 times for 100 took 0.27773557800000004 seconds
Running generator algorithm 1000000 times for 1000 took 0.041044322 seconds
Running formula algorithm 1000000 times for 1000 took 0.277931134 seconds
Running generator algorithm 1000000 times for 10000 took 0.051103143000000004 seconds
Running formula algorithm 1000000 times for 10000 took 0.276980175 seconds
Running generator algorithm 1000000 times for 100000 took 0.062019335 seconds
Running formula algorithm 1000000 times for 100000 took 0.276227007 seconds
Running generator algorithm 1000000 times for 1000000 took 0.07422898800000001 seconds
Running formula algorithm 1000000 times for 1000000 took 0.275485013 seconds
Running generator algorithm 1000000 times for 10000000 took 0.085803922 seconds
Running formula algorithm 1000000 times for 10000000 took 0.27701090500000003 seconds
Running generator algorithm 1000000 times for 100000000 took 0.09543419600000001 seconds
Running formula algorithm 1000000 times for 100000000 took 0.274908403 seconds
Running generator algorithm 1000000 times for 1000000000 took 0.10683704200000001 seconds
Running formula algorithm 1000000 times for 1000000000 took 0.27524084800000004 seconds
Running generator algorithm 1000000 times for 2000000000 took 0.13019867100000002 seconds
Running formula algorithm 1000000 times for 2000000000 took 0.274846384 seconds

In short, the generator algorithm way outperforms the formula based solution on all positive int values - even close to the maximum int value it is more than twice as fast! So much for belief based performance optimization ;-)

For the record, modifying the above code to use long variables instead of int, the generator algorithm becomes slower (as expected, since it has to add up long values now), and cutover point where the formula starts to be faster is around 1000000000000L, i.e. 1012.

Update2: As IVlad and Moron noted, I am not quite an expert in floating point calculations :-) based on their suggestions I improved the formula to this:

private static boolean isFibByFormula(long num)
{
    double power = (double)num * (double)num;
    double first = 5 * power + 4;
    double second = 5 * power - 4;

    return isWholeNumber(Math.sqrt(first)) || isWholeNumber(Math.sqrt(second));
}

This brought down the cutover point to approx. 108 (for the long version - the generator with int is still faster for all int values). No doubt that replacing the sqrt calls with something like suggested by @Moron would push down the cutover point further.

My (and IVlad's) point was simply that there will always be a cutover point, below which the generator algorithm is faster. So claims about which one performs better have no meaning in general, only in a context.

Péter Török
And the reason for the downvote is ...?
Péter Török
It seems everyone who was upvoted, and that didn't suggest what IVlad suggested has been downvoted by one. Draw your own conclusions.
David M
Just to clear things up, I didn't downvote. I'm not even 100% sure my solution is actually more efficient. I'm going to upvote yours and @David M's answers because they may in fact be better.
IVlad
Apologies for the insinuation IVlad. Several of us were downvoted without a reason being given - would the responsible party care to give us any feedback please?
David M
It's very fair of you @IVlad, thanks for the feedback. Apparently you (or @Soufiane) have a secret fan :-)
Péter Török
-1: There is no need of any fan business needed to downvote this answer. IMO, this answer is quite bad. If you want to generate fibonacci numbers and check >= n, at least do a binary search! It is _completely_ naive to just generate the sequence till you hit upon a number >= n. I am pretty sure that this answer is completely useless to OP. It is made worse by the statement: "You _need_ to generate ...". You don't 'need' to. You could, but you don't _have_ to.
Moron
... and before you ask, yes, you can generate the kth fibonacci number without having to generate all the previous ones, making binary search possible. Also, downvoting is sometimes done to get the good answers to the top. Sometimes, this means downvoting all but one answer.
Moron
@Moron, it is a naive but _working_ approach. Remember, this is homework, not a performance critical production system :-) And it _may_ even be optimal, depending on the context (see @IVlad's comment above) - have you actually done any performance measurement to see under which circumstances the formula shown in Ivlad's answer outperforms the sequence generation? If not, what are we talking about?
Péter Török
@Moron, two more things about this: _"downvoting is sometimes done to get the good answers to the top. Sometimes, this means downvoting all but one answer."_ 1) this sounds suspiciously close to [tactical downvoting](http://meta.stackoverflow.com/questions/24165/is-tactical-down-voting-ever-valid) 2) this is a ridiculous explanation for downvoting a _single_ answer having 1 score when the top answer has 12 ;-) Of course, feel free to downvote, I don't mind the points lost. What I _do_ mind is shaky reasoning.
Péter Török
@Peter: Not tactical downvoting at all. Many times people vote correct looking but _quite wrong_ answers, while the actually correct answers just languish at the bottom. The point of downvoting is to get quality answers to the top (search meta if you are not convinced). Downvoting while leaving a comment lets people know that an answer has flaws. As to downvoting this answer, it was to make a point. This answer is bad and the comments above appear to make you think it is not. Frankly, what is shaky reasoning is implying IVlad could be involved in tactical downvoting. IVlad's algorithm will...
Moron
... beat the crap out of your algorithm. We don't need to measure to figure that out. I agree for homework IVlad's algorithm might be overkill, but the point made was this is worse algorithm than that and I don't care if you think things need to be measured to find out that. If you are not convinced, I can't help you regarding that.
Moron
@Moron, "The point of downvoting is to get quality answers to the top" - IMO that's the point of _upvoting_. And if you think I was implying IVlad was the downvoter, read more carefully.
Péter Török
@Moron, as I said, feel free to think my answer is bad - that is your right, even if we disagree. The point of the question above was the problems with the OP's concrete algorithm implementation. My answer pointed out the root cause and explained the solution in terms of the currently used algorithm. So I still maintain that it is a useful answer.
Péter Török
@Peter: I wasn't implying that you implied IVlad was downvoter, I just called that shaky reasoning :-). Of course upvoting helps quality answers, that is obvious! What is your point? What I meant was, there are situations where wrong answers are upvoted too, and causes the good answers to go into oblivion. Downvoting and leaving a comment helps in that case. I suggest you read carefully what I wrote :-). btw, if you change the phrasing from 'You _need_ to..' to 'You _could_...', I will be glad to remove my downvote. Anyway, I apologize if I cause you some distress, I was only making a point.
Moron
@Peter: btw, about the implication of downvoting, you did imply downvoting was going on, but not necessarily by IVlad. And this has dragged on too long. I apologize for the noise and any distress. I will stop bothering you :-)
Moron
@Moron, see my update regarding the performance question. About the rest, it's OK, no hard feelings :-)
Péter Török
@Peter: Don't use Math.Sqrt or Math.Pow! :-) Use binary search for determining if 5f^2 +- 4 is a perfect square. Or better yet, use this: http://stackoverflow.com/questions/295579/fastest-way-to-determine-if-an-integers-square-root-is-an-integer
Moron
@Péter Török - no offense but using `Math.pow` for squaring a number is kind of obviously unfair and generally a bad idea :). Also, like @Moron said, `sqrt` can also be avoided, but I'd be curious what the results are if you just get rid of the `pow`.
IVlad
+1 for actually benchmarking instead of just guessing.
Frerich Raabe
With the benchmarking code, the -1 I gave is now well deserved! You can't just put any implementation in there and claim one is better than that other. This is getting silly.
Moron
@IVlad, see my update. @Moron, at least I tried to lean on facts instead of guesses. Measurements and experiments can be improved, belief can't.
Péter Török
@Peter: You don't need two sqrts calls. Also, there are atmost 40 fibonacci numbers below 10^8. Put them in a lookup table and the naive method can be beaten for small values too. Also, I posted some benchmark results which show that the cutoff on my machine is 50 (I suppose I have a FPU). Btw, claiming everything needs to be measured is just plain silly. How about measuring quicksort vs bogosort/bubblesort ? Perhaps you can find the cut-off and let us know and maybe shatter our beliefs? ;-)
Moron
@Moron, good point about sqrt. The table-based lookup is a very good solution indeed... but let me point out that it is a new, third algorithm. Regarding quicksort, how does everyone know that it is (in general) quicker than bubble sort? Maybe because someone, somewhere, has already explicitly proven it (by measurement and/or mathematical proof)? :-) Your benchmarks actually show very clearly why measurements are needed - eliminating one sqrt call does not explain all the difference in the results. Even the same algorithm can perform wildly differently on different platforms.
Péter Török
You very likely have a mathematical proof somewhere coupled with empirical evidence. That empirical data is probably useless for today's machines, while the proof is valid. Measurements are always finite and can only go so far (systems changing etc) and depend on the implementation/underlying machine etc and can never be considered proof. All they prove is that for that set of data on that machine, at the point in time, algorithm A is better than B. They are important, no doubt, but they are just a tool. You don't always have to measure to compare.
Moron
Of course, you change the machine and things might change. For instance, if I had a machine where a jump call was very expensive, your method will probably crawl. The fact of the matter is, we have to agree upon a common model before we even talk about comparing. When we don't talk about it, I suppose it is reasonable to assume some reasonably common processor like today's intel processors, in which case, IMO, we can pretty much prove that the sqrt method will outperform the naive method starting at reasonably small n.
Moron
btw, I just noticed that you changed the wording. I have removed the -1.
Moron
@Moron, I see your point, now that you actually explain it ;-) And - surprise, surprise - mostly agree with it... with one note: for comparison you need to define concrete criteria. One possible criteria is _"the lower the big O, the better"_ - that would be yours if I am not mistaken. Another is _"the closest to the OP's original approach, the better"_ - that was mine. Obviously these are contradicting in this case (and there can be any number more)... so algorithm A can only be better than algorithm B according to certain criteria, not "in general".
Péter Török
@Moron, I see you added a very similar comment while I added mine... yes, those implicit assumptions did bother me from the start of our conversation. Now that you made them explicit, we can finally agree :-)
Péter Török
going to read this comments tastefully. It seems like everyone wants explanation when downvoted without reason, but few partecipates in suggesting a way to make it better; I would go for forcing comments for downvotes, but this has harsh opposition on metaSO. +1 for the efforts and since: how people can consider this answer unuseful?
ShinTakezou
(read; even in its initial state and slippery wording, I think the OP could find it useful, so the removed -1 luckly was removed, but still there's a unsenseful -1. bah)
ShinTakezou
+19  A: 

Read the section titled "recognizing fibonacci numbers" on wikipedia.

Alternatively, a positive integer z is a Fibonacci number if and only if one of 5z^2 + 4 or 5z^2 − 4 is a perfect square.[17]

Alternatively, you can keep generating fibonacci numbers until one becomes equal to your number: if it does, then your number is a fibonacci number, if not, the numbers will eventually become bigger than your number, and you can stop. This is pretty inefficient however.

IVlad
Just curious, how big does this number have to be before it is more inefficient than a square root operation?
Chris J
@Chris J - good question. Generating the first `n` fibonacci numbers is an `O(n)` time operation. Extracting the square root of `z` is `O(log z)`. I'm inclined to say that for `n` big enough for the fibonacci numbers to require big ints, the square root is faster, but I'm not sure.
IVlad
subsequent values in the Fibonacci sequence approach a very particular ratio (the Golden one). therefore, they can be roughly approximated as that ratio^the number of steps to reach the number (with some constant factors). i.e. log(z) ~ n log(phi) - that would indicate that taking the square root and simply counting up are pretty close.However, I think the advantage might be that one can assess the non-integer-ness of a square root (that's hand-waving, not exactly sure) in less than log(z).
Carl
+2  A: 

A positive integer x is a Fibonacci number if and only if one of 5x^2 + 4 and 5x^2 - 4 is a perfect square

Soufiane Hassou
do you have a reference for that formula? is that even correct?
Chris J
Recognising Fibonacci numbers:http://en.wikipedia.org/wiki/Fibonacci_number#Recognizing_Fibonacci_numbers
StevenH
A: 

I don't know if there is an actual formula that you can apply to the user input however, you can generate the fibonacci sequence and check it against the user input until it has become smaller than the last number generated.

int userInput = n;
int a = 1, b = 1;

while (a < n) {
  if (a == n)
    return true;

  int next = a + b;
  b = a;
  a = next;
}

return false;
Chris J
A: 

If my Java is not too rusty...

static bool isFib(int x) {
    int a=0;
    int b=1;
    int f=1;
    while (b < x){
        f = a + b;
        a = b;
        b = f;
    }
    return x == f;
}
Iacopo
+1  A: 

Trying to leverage the code you have already written I would propose the following first, as it is the simplest solution (but not the most efficient):

private static void main(string[] args)
{
    //This will determnine which numbers between 1 & 100 are in the fibonacci series
    //you can swop in code to read from console rather than 'i' being used from the for loop
    for (int i = 0; i < 100; i++)
    {
        bool result = isFib(1);

        if (result)
            System.out.println(i + " is in the Fib series.");

        System.out.println(result);
    }

}

private static bool isFib(int num)
{
    int counter = 0;

    while (true)
    {
        if (fib(counter) < num)
        {
            counter++;
            continue;
        }

        if (fib(counter) == num)
        {
            return true;
        }

        if (fib(counter) > num)
        {
            return false;
        }
    }
}

I would propose a more elegant solution in the generation of fibonacci numbers which leverages recursion like so:

public static long fib(int n) 
{
   if (n <= 1) 
      return n;
   else 
      return fib(n-1) + fib(n-2);
}

For the extra credit read: http://en.wikipedia.org/wiki/Fibonacci_number#Recognizing_Fibonacci_numbers

You will see the that there are a few more efficient ways to test if a number is in the Fibonacci series namely: (5z^2 + 4 or 5z^2 − 4) = a perfect square.

//(5z^2 + 4 or 5z^2 − 4) = a perfect square 
//perfect square = an integer that is the square of an integer
private static bool isFib(int num)
{
    double first = 5 * Math.pow((num), 2) + 4;
    double second = 5 * Math.pow((num), 2) - 4;

    return isWholeNumber(Math.sqrt(first)) || isWholeNumber(Math.sqrt(second));
}

private static bool isWholeNumber(double num)
{
    return num - Math.round(num) == 0;    
}
StevenH
As shown by Péter Török in another answer to this question, testing for a perfect square is only for sufficiently large large numbers (around 1000000000000 and beyond, in his benchmarks). Of course, it could become faster for lower values if you replace the check for whether a number is a perfect square with something more efficient.
Frerich Raabe
@Frerich: No offense to Peter but his implementation of sqrt check sucks and is practically of no use in benchmarking.
Moron
@Moron, I don't claim it mine - it was copy-pasted straight from here :-)
Péter Török
@Peter: I see. I apologize :-)
Moron
+1  A: 

There are a number of methods that can be employed to determine if a given number is in the fibonacci sequence, a selection of which can be seen on wikipedia.

Given what you've done already, however, I'd probably use a more brute-force approach, such as the following:

  1. Generate a fibonacci number
  2. If it's less than the target number, generate the next fibonacci and repeat
  3. If it is the target number, then success
  4. If it's bigger than the target number, then failure.

I'd probably use a recursive method, passing in a current n-value (ie. so it calculates the nth fibonacci number) and the target number.

Edd
A: 

You can do this in two ways , the recursive and mathematical. the recursive way start generating fibonacci sequence until you hit the number or pass it the mathematical way nicely described here ... http://www.physicsforums.com/showthread.php?t=252798

good luck.

Stas
+1  A: 

Ok. Since people claimed I am just talking thin air ('facts' vs 'guesses') without any data to back it up, I wrote a benchmark of my own.

Not java, but C# code below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SO
{
    class Program
    {
        static void Main(string[] args)
        {
            AssertIsFibSqrt(100000000);

            MeasureSequential(1);
            MeasureSqrt(1);

            MeasureSequential(10);
            MeasureSqrt(10);

            MeasureSequential(50);
            MeasureSqrt(50);

            MeasureSequential(100);
            MeasureSqrt(100);


            MeasureSequential(100000);
            MeasureSqrt(100000);

            MeasureSequential(100000000);
            MeasureSqrt(100000000);

        }

        static void MeasureSequential(long n)
        {
            int count = 1000000;
            DateTime start = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                IsFibSequential(n);
            }
            DateTime end = DateTime.Now;

            TimeSpan duration = end - start;

            Console.WriteLine("Sequential for input = " + n + 
                              " : " + duration.Ticks);
        }

        static void MeasureSqrt(long n)
        {
            int count = 1000000;

            DateTime start = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                IsFibSqrt(n);
            }
            DateTime end = DateTime.Now;

            TimeSpan duration = end - start;

            Console.WriteLine("Sqrt for input =  " + n + 
                              " : " + duration.Ticks);
        }

        static void AssertIsFibSqrt(long x)
        {

            Dictionary<long, bool> fibs = new Dictionary<long, bool>();
            long a = 0;
            long b = 1;
            long f = 1;

            while (b < x)
            {
                f = a + b;
                a = b;
                b = f;

                fibs[a] = true;
                fibs[b] = true;
            }

            for (long i = 1; i <= x; i++)
            {
                bool isFib = fibs.ContainsKey(i);

                if (isFib && IsFibSqrt(i))
                {
                    continue;
                }

                if (!isFib && !IsFibSqrt(i))
                {
                    continue;
                }

                Console.WriteLine("Sqrt Fib test failed for: " + i);
            }
        }
        static bool IsFibSequential(long x)
        {
            long a = 0;
            long b = 1;
            long f = 1;

            while (b < x)
            {
                f = a + b;
                a = b;
                b = f;
            }
            return x == f;
        }

        static bool IsFibSqrt(long x)
        {
            long y = 5 * x * x + 4;

            double doubleS = Math.Sqrt(y);

            long s = (long)doubleS;

            long sqr = s*s;

            return (sqr == y || sqr == (y-8));
        }
    }
}

And here is the output

Sequential for input = 1 : 110011
Sqrt for input =  1 : 670067

Sequential for input = 10 : 560056
Sqrt for input =  10 : 540054

Sequential for input = 50 : 610061
Sqrt for input =  50 : 540054

Sequential for input = 100 : 730073
Sqrt for input =  100 : 540054

Sequential for input = 100000 : 1490149
Sqrt for input =  100000 : 540054

Sequential for input = 100000000 : 2180218
Sqrt for input =  100000000 : 540054

The sqrt method beats the naive method when n=50 itself, perhaps due to the presence of hardware support on my machine. Even if it was 10^8 (like in Peter's test), there are at most 40 fibonacci numbers under that cutoff, which could easily be put in a lookup table and still beat the naive version for the smaller values.

Also, Peter has a bad implementation of the SqrtVersion. He doesn't really need to compute two square roots or compute powers using Math.Pow. He could have atleast tried to make that better before publishing his benchmark results.

Anyway, I will let these facts speak for themselves, instead of the so called 'guesses'.

Moron