简体   繁体   中英

C++ Fibonacci number generator not working. Why?

I just wanna know why does this method to get the fibonacci number not work thanks.

#include <iostream>
#include <cctype>
#include <cmath>
using namespace std;

int fibonacci()
{
    cout << "enter sequence num: " << endl;
    int num;
    cin >> num;
    int list[num] = {0, 1};
    int x;

    if (num == 1)
    {
        cout << "the " << num << " fibo num is " << 0 << endl;
    }
    else if (num == 2)
    {
        cout << "the " << num << " fibo num is " << 1 << endl;
    }
    else
    {
        for (int y = 0; y < num - 2; y++)
        {
            // get new fibo value

            x = list[y] + list[y + 1];
            for (int z = 2; z < num; z++)
            {
                // will append new value to the list

                list[z] = x;
            }
        }
        cout << "the " << num << " fibo num is " << list[-1] << endl;
        // get the last value which is the fibo value
    }
}

int main()
{
    fibonacci();

    return 0;
}

For starters variable length arrays as that

cin>>num;
int list[num] = {0,1};

are not a standard C++ feature. In fact to calculate a Fibonacci number there is no need to use an array.

Moreover this declaration

int list[num] = {0, 1};

will be invalid if the entered value of the variable num will be equal to 1 . And even in C where variable length arrays are conditionally supported you may not initialize a variable length array in its declaration.

Nevertheless in this statement

cout<<"the "<<num<<" fibo num is "<<list[-1]<<endl;

the expression list[-1] accesses memory outside the array invoking undefined behavior.

It seems you mean

cout<<"the "<<num<<" fibo num is "<<list[num-1]<<endl;

I would define the function the following way as shown in the demonstration program below.

#include <iostream>
#include <utility>

unsigned long long Fibonacci( unsigned int n )
{
    unsigned long long first = 0, second = 1;

    for ( unsigned i = 0; i < n; i++ )
    {
        first = std::exchange( second, first + second );
    }

    return first;
}


int main()
{
    const unsigned int N = 10;

    for ( unsigned int i = 0; i < N; i++ )
    {
        std::cout << i << ": " << Fibonacci( i ) << '\n';
    }
}

The program output is

0: 0
1: 1
2: 1
3: 2
4: 3
5: 5
6: 8
7: 13
8: 21
9: 34

The problems in your code have already been shown by Vlad from Moscow.

I would like to add, that there is no need at all to calculate Fibonacci numbers at runtime. The compiler will be your friend.

The ultrafast and compact solution is to use compile time calculation. So, precalculate all possible values, that fit into a 64 unsigned bit, value during compile time.

One important property of the Fibonacci series is that the values grow strongly exponential. So, all existing build in integer data types will overflow rather quick.

With Binet's formula you can calculate that the 93rd Fibonacci number is the last that will fit in a 64bit unsigned value.

And calculating 93 values during compilation is a really simple and fast task.

So, how to do?

We will first define the default approach for calculation a Fibonacci number as a constexpr function. Iterative and non recursive.

// 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;
}

With that, Fibonacci numbers can easily be calculated at compile time. Then, we fill a std::array with all Fibonacci numbers. We use also a constexpr and make it a template with a variadic parameter pack.

We use std::integer_sequence to create a Fibonacci number for indices 0,1,2,3,4,5, ....

That is straigtforward and not complicated:

template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
    return std::array<unsigned long long, sizeof...(ManyIndices)>{ { getFibonacciNumber(ManyIndices)... } };
};

This function will be fed with an integer sequence 0,1,2,3,4,... and return a std::array<unsigned long long, ...> with the corresponding Fibonacci numbers.

We know that we can store maximum 93 values. And therefore we make a next function, that will call the above with the integer sequence 1,2,3,4,...,92,93, like so:

constexpr auto generateArray() noexcept {
    return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}

And now, finally,

constexpr auto FIB = generateArray();

will give us a compile-time std::array<unsigned long long, 93> with the name FIB containing all Fibonacci numbers. And if we need the i'th Fibonacci number, then we can simply write FIB[i] . There will be no calculation at runtime.

I do not think that there is a faster or easier way to calculate the n'th Fibonacci number.

Please see the complete program below:

#include <iostream>
#include <array>
#include <utility>
// ----------------------------------------------------------------------
// 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) {
    // 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 numberscompile 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 in an 64bit unsigned value (Binets 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();
// ----------------------------------------------------------------------

// Test
int main() {

    // Print all possible Fibonacci numbers
    for (size_t i{}; i < MaxIndexFor64BitValue; ++i)

        std::cout << i << "\t--> " << FIB[i] << '\n';

    return 0;
}

Developed and tested with Microsoft Visual Studio Community 2019, Version 16.8.2.

Additionally compiled and tested with clang11.0 and gcc10.2

Language: C++17

There is some inconsistent indexing here. If num = 1, the fibonacci number is 0, and if num=2, the fibonacci number is 1... but this does not quite match the declaration int list[num] = {0,1}, as indexes start with 0.

I have rewritten the code so that the first number has an index of 1 (list[1]=0 and list[2]=1)

A nested-for loop is not needed to append the new sum at the end of the array. Just a simple for loop will do.

I have modified your code below, see below.

#include <iostream>
#include <cctype>
#include <cmath>
using namespace std;

int fibonacci(){
   cout<<"enter sequence num: "<<endl;
   int num;
   cin>>num;
   int list[num];
   list[1] = 0;
   list[2] = 1;
   int x;

   if(num==1){
       cout<<"the "<<num<<" fibo num is "<<0<<endl;
   }else if(num==2){
       cout<<"the "<<num<<" fibo num is "<<1<<endl;
   }else{
       for(int y=3;y<=num;y++){ 
              list[y]=list[y-1]+list[y-2];
       }
   }
   cout<<"the "<<num<<" fibo num is "<<list[num]<<endl; 
   
}

int main()
{
   fibonacci();
   return 0;
} 

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM