【问题标题】:Calculating mod m for large Fibonacci numbers计算大斐波那契数的 mod m
【发布时间】:2019-06-24 02:06:41
【问题描述】:

我收到两个警告(缩小转换 && 控制可能到达非 void 函数的结尾),代码如下。然而,代码会编译,当我运行它时它会给出以下消息:Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

代码是在 Ubuntu 上使用 CLion 编译的

// calculate F(n) mod m   

#include <iostream>
#include <cmath>

long long Fiobonacci(long long n) { // Fast calculation of Fibonacci number using 'fast doubling'

    if (n == 0)
        return 0;
    else if (n % 2 == 0)
        return Fiobonacci(n / 2) * (2 * Fiobonacci(n / 2 + 1) - Fiobonacci(n / 2));
    else
        return std::pow(Fiobonacci((n + 1) / 2), 2) + std::pow(Fiobonacci((n - 1) / 2), 2);
}

long long GetPissanoPeriod(long long m){
    for (long long i = 0; i <= 6 * m ; ++i){
        if (Fiobonacci(i) % m == 0){ // if an element is zero it might be followed by a 1
            if(Fiobonacci(i+1) % m == 1)
                return i+1;
        }
    }
}

int main() {
    long long n, m;
    std::cin >> n >> m;
    long long period = GetPissanoPeriod(m);
    long long res = Fiobonacci(n % period) % m;
    std::cout << res << 'n';
}

【问题讨论】:

  • 你意识到如果m 是一个素数,你可以用 Zm(也就是整数 mod m)做所有的数学运算并得到相同的结果。如果m不是素数,我想你可以把它分解成素数,然后在每个Zp中进行计算后使用中国剩余定理得到结果。
  • @RezaAfra return std::pow(Fiobonacci((n + 1) / 2), 2) -- Do not use pow() for integer exponentiation
  • 此外,您可以利用memoization,而不必为相同的输入重新计算Fibonacci。将 Fibonacci(n) 的预计算值存储在一个表中,然后将其用作缓存可能会加快此代码的速度。
  • 我应该看到的! 打额头 是的,一般来说,如果你正在用整数做数学运算并且你需要#include &lt;math&gt; 来做某事,那么你可能做错了什么。 &lt;math&gt; 中的几乎所有内容都用于 floatdouble
  • @Omnifarious 你的意思是&lt;cmath&gt;

标签: c++ c++17 fibonacci


【解决方案1】:

请看下面修改后的代码。

 #include <iostream>
 #include <cmath>
 using namespace std;
 long long pow2(long long x)
 {
     return x * x;
  }
 long long Fibonacci(long long n) { // Fast calculation of Fibonacci number using 'fast doubling'

         if (n == 0)
                 return 0;
         else if(n <= 2)
                 return 1;
         else if (n % 2 == 0)
                 return Fibonacci(n / 2) * (2 * Fibonacci(n / 2 + 1) - Fibonacci(n / 2));
        else
                 return pow2(Fibonacci((n/2 + 1) / 2), 2) + pow2(Fibonacci((n / 2)), 2);
}

 long long GetPisanoPeriod(long long m){
         for (long long i = 2; i <= m * m ; ++i){
                 if (Fibonacci(i) % m == 0){ // if an element is zero it might be followed by a 1
                         if(Fibonacci(i+1) % m == 1){
                                return i - 1;
                         }
                 }
         }
 return 1;
 }
 int main() {
         long long n, m;
         std::cin >> n >> m;
         long long period = GetPisanoPeriod(m);
         long long res = Fibonacci(n % period) % m;
         std::cout << "res" << res<<endl;
 }

控件可能到达非空函数错误是由于没有从 GetPisanoPeriod 返回值。正如@JaMiT 指出的那样

分段错误是由于斐波那契函数的终止条件不正确。 斐波那契数列定义如下。

  Fn = Fn-1 + Fn-2

带有种子值

  F0 = 0 and F1 = 1

意思是n = 0和n = 1应该有一个终止条件。 对于 n = 2 你不必调用递归可以简单地返回 1。

除此之外,如您所见,斐波那契计算公式进行了更正。 在 GetPisanoPeriod 控件必须从 2 开始。否则它会一直返回 0。

【讨论】:

  • 代码中不要放行号,以免别人复制代码尝试
  • 这里也应该避免::std::pow。它在 C++11 中进行了模板化,但结果始终是某种浮点类型,这可能在这种情况下有效,但大多是偶然的。
  • 仅供参考,this is your code 删除了 std::pow,加上缓存优化。由于没有测试数据,我假设这段代码可以正常工作(但不能保证)。
猜你喜欢
  • 2017-02-27
  • 1970-01-01
  • 2013-03-31
  • 2016-10-12
  • 1970-01-01
  • 1970-01-01
  • 2020-01-18
  • 2017-01-29
  • 1970-01-01
相关资源
最近更新 更多