为什么计算错误的皮萨诺时期

时间:2020-05-04 10:14:56

标签: c++ c++11

    long long fibonacci_fast(long long n) {

    long long a[n]{0};
    a[0]=0;
    a[1]=1;
    for(int i=2;i<=n;i++)
        a[i]=a[i-1]+a[i-2];

    return a[n];
}

计算pisano周期的函数是

long long get_pisano_period(long long n,long long m){
    vector<long long> vec{0,1};

    for(int i=2;i<=n;i++){
        vec.push_back(fibonacci_fast(i)%m);


    long c{2};

    for(int i=2;i<=n;i++){
    if((vec[i]!=0) && (vec[i+1]!=1)){
    c++;
    }}
    return c;
}

在主函数中,我只是输出get_pisano_period(n,m)的输出

1 个答案:

答案 0 :(得分:1)

代码尝试根据给定模数和看似极限的方式来评估Pisano周期(斐波纳契数列取模n 的周期),但是存在多个问题。 / p>

  • fibonacci_fast中,a被声明为可变长度数组,这是C ++中的非标准编译器扩展。它也会被初始化,即使使用C99也需要另一个编译器扩展。在这种情况下,应使用std::vector

  • 在同一函数中,a也在循环中(最后一次迭代)以及返回a[n]时也被无界访问。

  • get_pisano_period中,还有另一个不确定行为的来源,内循环遍历vecn + 1,而其大小为i + 2

逻辑错误也很严重。

  • fibonacci_fast在不使用模数的情况下计算的斐波那契数,以便这些值不受限制。

  • 仅在将fibonacci_fast返回的值推入vec函数内的get_pisano_period中之前应用模,但这会生成错误的序列。

  • 考虑到get_pisano_period中的用法,_fast名称的fibonacci_fast部分是一个谎言,因为该函数在外部循环中每次都被调用它会生成(并删除)直到递增的i为止的所有数字。

  • 此外,以下循环检查对夫妇的后续值(让我们忽略已提到的UB)并计算非{0, 1}的夫妇对,而函数应找到重复序列后,立即检查最后两个值和 break

如果我们只需要句点并且不需要存储序列以备将来使用,则可以仅存储和更新最后两个数字,而无需使用向量。

long long pisano_period(long long m, long long limit = 2048)
{
    long long fib_prev{0}, fib{1};

    if ( m < 2 )
        return 1;

    for (long long count{2}; count < limit; ++count)
    {
        // Evaluate the next Fibonacci number modulo m without any array or function call
        long long fib_next{
            (fib_prev + fib) % m
        };

        // If the sequence is repeating, the loop should stop.
        if ( fib == 0  &&  fib_next == 1 )
            return count - 1;

        // It stores only the two last values, so it has to update them.
        fib_prev = fib;
        fib = fib_next;
    }
    std::cerr << "Warning: limit reached.\n";
    return limit;
}

可测试的here