【问题标题】:C print first million Fibonacci numbersC 打印第一个百万斐波那契数
【发布时间】:2016-02-17 10:35:14
【问题描述】:

我正在尝试编写将打印前 100 万个斐波那契数的 C 代码。

实际的问题是我想得到F(1,000,000)的最后10位

我了解序列的工作原理以及如何编写代码来实现这一点,但是由于 F(1,000,000) 非常大,我正在努力寻找一种表示它的方法。

这是我正在使用的代码:

#include<stdio.h>
 
int main()
{
   unsigned long long n, first = 0, second = 1, next, c;
 
   printf("Enter the number of terms\n");
   scanf("%d",&n);
 
   printf("First %d terms of Fibonacci series are :-\n",n);
 
   for ( c = 0 ; c < n ; c++ )
   {
      if ( c <= 1 )
         next = c;
      else
      {
         next = first + second;
         first = second;
         second = next;
      }
      printf("%d\n",next);
   }
 
   return 0;
}

我正在使用long long 尝试确保有足够的位来存储数字。

这是第一个 100 数字的输出:

First 100 terms of Fibonacci series are :-                                                                                                                                     

    0                                                                                                                                                                              
    1                                                                                                                                                                              
    1                                                                                                                                                                              
    2                                                                                                                                                                              
    3                                                                                                                                                                              
    5                                                                                                                                                                              
    8                                                                                                                                                                              
    13                                                                                                                                                                             
    21                                                                                                                                                                             
    34                                                                                                                                                                             
    55                                                                                                                                                                             
    89                                                                                                                                                                             
    144                                                                                                                                                                            
    233                                                                                                                                                                            
    377                                                                                                                                                                            
    610                                                                                                                                                                            
    987                                                                                                                                                                            
    1597                                                                                                                                                                           
    2584                                                                                                                                                                           
    4181                                                                                                                                                                           
    6765                                                                                                                                                                           
    10946                                                                                                                                                                          
    17711                                                                                                                                                                          
    28657                                                                                                                                                                          
    46368                                                                                                                                                                          
    75025                                                                                                                                                                          
    121393                                                                                                                                                                         
    196418                                                                                                                                                                         
    317811                                                                                                                                                                         
    514229                                                                                                                                                                         
    832040                                                                                                                                                                         
    1346269                                                                                                                                                                        
    2178309                                                                                                                                                                        
    3524578                                                                                                                                                                        
    5702887                                                                                                                                                                        
    9227465                                                                                                                                                                        
    14930352                                                                                                                                                                       
    24157817                                                                                                                                                                       
    39088169                                                                                                                                                                       
    63245986
    102334155                                                                                                                                                                      
    165580141                                                                                                                                                                      
    267914296                                                                                                                                                                      
    433494437                                                                                                                                                                      
    701408733                                                                                                                                                                      
    1134903170                                                                                                                                                                     
    1836311903                                                                                                                                                                     
    -1323752223                                                                                                                                                                    
    512559680                                                                                                                                                                      
    -811192543                                                                                                                                                                     
    -298632863                                                                                                                                                                     
    -1109825406                                                                                                                                                                    
    -1408458269
    ...

截断了输出,但你可以看到问题,我相信生成的数字的大小导致值溢出为负数。老实说,我不明白如何阻止它。

谁能指出我如何实际处理这种大小的数字的正确方向?

我没有尝试打印第一个百万,因为如果它在打印 F(100) 时失败,那么它打印 F(1,000,000) 的希望不大。

【问题讨论】:

  • 长长的还不够!
  • 一个long long 至少应该高于1836311903
  • @BasileStarynkevitch 我认为你过于苛刻了。初学者可能没有足够的模运算经验来意识到整个计算可以在 10^10 模下进行。对程序员来说显而易见的事情对学生来说并不总是显而易见的。
  • 使用%lld 格式说明符而不是%d,但这只会让您更进一步。但无论如何,下面的答案非常全面。

标签: c fibonacci


【解决方案1】:

Binet's Formula 第 n 个斐波那契数大约是黄金比例(大约 1.618)的 n 次方,然后除以 5 的平方根。简单使用对数表明,第 100 万个斐波那契数因此超过 200,000位数。因此,前一百万个斐波那契数之一的平均长度超过 100,000 = 10^5。因此,您试图打印 10^11 = 1000 亿位数字。我认为您需要的不仅仅是一个大型 int 库。

另一方面,如果您想简单地计算第 100 万个数字,您可以这样做,但最好使用一种不计算所有中间数字的方法(因为简单地计算而不是对于足够大的 n),将它们全部打印出来仍然是不可行的。众所周知(参见this),第n 个斐波那契数是矩阵[[1,1],[1,0]] 的n 次方的4 个条目之一。如果您将exponentiation by squaring(也适用于矩阵幂,因为矩阵乘法是关联的)与一个好的大 int 库一起使用,那么计算第 100 万个斐波那契数就变得非常可行。

[进一步编辑]:这是一个 Python 程序,用于计算非常大的斐波那契数,修改为现在接受一个可选的模数。在引擎盖下,它使用了一个很好的 C bignum 库。

def mmult(A,B,m = False):
    #assumes A,B are 2x2 matrices
    #m is an optional modulus
    a = A[0][0]*B[0][0] + A[0][1]*B[1][0]
    b = A[0][0]*B[0][1] + A[0][1]*B[1][1]
    c = A[1][0]*B[0][0] + A[1][1]*B[1][0]
    d = A[1][0]*B[0][1] + A[1][1]*B[1][1]
    if m:
        return [[a%m,b%m],[c%m,d%m]]
    else:
        return [[a,b],[c,d]] 

def mpow(A,n,m = False):
    #assumes A is 2x2
    if n == 0:
        return [[1,0],[0,1]]
    elif n == 1: return [row[:] for row in A] #copy A
    else:
        d,r = divmod(n,2)
        B = mpow(A,d,m)
        B = mmult(B,B,m)
        if r > 0:
            B = mmult(B,A,m)
        return B

def Fib(n,m = False):
    Q = [[1,1],[1,0]]
    return mpow(Q,n,m)[0][1]

n = Fib(999999)
print(len(str(n)))
print(n % 10**10)
googol = 10**100
print(Fib(googol, googol))

输出(添加空格):

208988

6684390626

3239047153240982923932796604356740872797698500591032259930505954326207529447856359183788299560546875

请注意,你称之为第 100 万个斐波那契数,我称之为第 999,999 个——因为更标准的做法是从 1 作为第一个斐波那契数开始(如果你想将它算作斐波那契数,则将第 0 称为第 0 个) )。第一个输出数字确认该数字中有超过 200,000 个数字,第二个输出数字是最后 10 个数字(这不再是一个谜)。最终数字是 googolth 斐波那契数的最后 100 位数字——在几分之一秒内计算得出。我还不能做一个 googolplex :)

【讨论】:

  • 最好不要声明堆栈数组,然后.. :)
  • @BasileStarynkevitch 正确,我只关心F(1,000,000) 的最后 10 位数字
  • @ChrisEdwards:那么你可能会先做一些数学运算(计算模数 10^10),但你应该在你的问题中说明它变得非常不同:'如何计算 F(1000000) 的最后 10 位数字?'
  • @chqrlie 简单的迭代方法在一定程度上起作用。我刚刚尝试了 1,000,000 次,在我的机器上花了大约 8 秒(与基于矩阵的方法相比不到一秒,这可以提高效率)。对于 10,000,000,我的方法只需不到 10 秒。我已经有超过 5 分钟的迭代方法,现在为 10,000,000 并且当我完成此评论时可能会终止该过程。我的直觉是,我会在一百万之前撞墙,但你说得对,一百万本身并不是不合理的。感谢您指出这一点。
  • 如有疑问,请尝试蛮力...或更好:首先尝试蛮力 ;-)
【解决方案2】:

您需要 Fib(1000000) 的最后 10 位数字。阅读有关Fibonacci numbers 的更多信息(并阅读两次)。

不用多想,您可以使用一些bignum 库,例如GMPlib。您将使用 few mpz_t bigint 变量循环计算 Fib(1000000)(您当然不需要一百万个 mpz_t 的数组,但少于手指的 mpz_t 变量在你的手中)。当然,您不会打印所有的斐波那契数字,只会打印最后 1000000th 个(所以今天便宜的笔记本电脑有足够的内存,并且会在不到一个小时内吐出那个数字)。作为John Coleman answered,它有大约 200K 位(即 2500 行,每行 80 位)。

(顺便说一句,当考虑一个程序产生一些大输出时,你最好猜测-估计该输出的典型大小和获得它的典型时间;如果它不适合你的桌面房间 -或者你的台式电脑——你有一个问题,也许是一个经济问题:你需要购买更多的计算资源)

请注意,高效的 bignum 算术是一个很难的主题。存在用于 bignum 算法的聪明算法,它们比您想象的幼稚算法要高效得多。

实际上,您不需要任何大整数。阅读一些关于modular arithmetic 的数学教科书。总和(或乘积)的模数与模数的总和(或乘积)一致。使用该属性。 10 位整数适合 64 位 int64_t 所以有些人认为你不需要任何 bignum 库。

(我想稍微多想一下,你不需要任何计算机或任何 C 程序来计算它。一个便宜的计算器,一支铅笔和一张纸就足够了,而且可能不需要计算器完全没有。)

编程时(或解决数学题)要学习的一课是在开始编码之前思考问题尝试重新表述问题。 J.Pitrat(法国人工智能先驱,现已退休,但仍在使用他的计算机)有几个有趣的blog 条目与此相关:Is it possible to define a problem?When Donald and Gerald meet Robert 等。

理解和思考问题(以及子问题!)是软件开发的一个有趣部分。如果您从事软件开发工作,您将首先被要求解决现实世界的问题(例如,制作销售网站或自动吸尘器),您需要考虑将这个问题转化为可在计算机。耐心点,你需要ten years to learn programming

【讨论】:

  • 添加关于最后 10 位数字的规定改变了一切。您当然是正确的,不需要 bignum 库。
  • +1 特别。关于解决问题的一点。对计算机进行编程以做某事很容易......决定对它们进行编程做什么是困难的部分!
  • +1 鼓励 OP 走上正轨。雅克·皮特拉 (Jacques Pitrat) 的退休是我可以理解的:他不会停止涉足人工智能。阅读他对 Michel Berry 的立场非常有趣!两者都是非凡的头脑,但风格却如此不同。编程就像好酒:成为一名熟练的程序员确实需要 10 年,但不是每个人都这样做,最好的人一辈子都在学习,孜孜不倦地追求优雅、简单和正确。
【解决方案3】:

要“获取 F(1,000,000) 的最后 10 位数字”,只需在计算 next 时应用余数函数 % 并使用正确的格式说明符:"%llu"

没有必要将比 10 个最低有效数字更重要的数字相加。

  // scanf("%d",&n);
  scanf("%llu",&n);
  ...
  {
     // next = first + second;
     next = (first + second) % 10000000000;
     first = second;
     second = next;
  }
  // printf("%d\n",next);
  printf("%010llu\n",next);

我的输出(将最后 5 位数字删掉以不泄露最终答案)

 66843xxxxx

【讨论】:

  • 最好不要完全放弃它。当我最初回答时,我给出了与 OP 询问的那个相邻的斐波那契数。在编辑时,我得到了正确的数字,但按照你的引导并屏蔽了最后 5 位数字。
  • @John Coleman 同意。一个小谜团让它变得有趣。
  • 通常0 被认为是斐波那契的第 0 个值,1 是第一个值,等等。所以从技术上讲,66843xxxxx 将是第 999999 个数字,82425xxxxx 将是第 1000000 个数字。
  • @Hetzroni 关于Fibonacci 及其通常是第一个元素的变体是正确的。 C 中的“第一个”概念通常会导致非 1 的结果。 C 数组的第一个元素使用0 进行索引。 IAC、OP 可以根据需要进行多次迭代。也许这是一个who's on first? 的困境?
【解决方案4】:

这个问题毫无疑问来自一些编程比赛,你必须仔细阅读这些问题。

第 100 万个斐波那契数是巨大的。大概有 200,000 位数左右。打印第一个 1,000,000 斐波那契数将杀死整个森林。但请仔细阅读:没有人要求您提供第 100 万个斐波那契数。您被要求输入该号码的最后十位

那么,如果你有 Fib(n-2) 和 Fib(n-1) 的后 10 位,你怎么能找到 Fib(n) 的后 10 位呢?如何在不计算数字本身的情况下计算斐波那契数的最后十位?

PS。您不能用 %d 打印长长的数字。使用 %lld。

【讨论】:

    【解决方案5】:

    您的算法实际上是正确的。由于您使用的是unsigned long long,因此您有足够的数字来捕获最后 10 位数字,并且无符号溢出函数的性质为模算术,因此您将获得至少最后 10 位数字的正确结果。

    问题在于您用于输出的格式说明符:

    printf("%d\n",next);
    

    %d 格式说明符需要 int,但您传递的是 unsigned long long。使用错误的格式说明符会调用undefined behavior

    在这种特殊情况下,最有可能发生的是printf 正在获取next 的低位4 字节(因为您的系统似乎是小端序)并将它们解释为已签名的int。这最终会显示大约前 60 个数字的正确值,但之后显示不正确的值。

    使用正确的格式说明符,你会得到正确的结果:

    printf("%llu\n",next);
    

    阅读/打印n时也需要这样做:

    scanf("%llu",&n);
    
    printf("First %llu terms of Fibonacci series are :-\n",n);
    

    这是数字 45-60 的输出:

    701408733
    1134903170
    1836311903
    2971215073
    4807526976
    7778742049
    12586269025
    20365011074
    32951280099
    53316291173
    86267571272
    139583862445
    225851433717
    365435296162
    591286729879
    956722026041
    

    【讨论】:

      猜你喜欢
      • 2016-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-04
      • 2019-06-26
      • 2012-02-15
      相关资源
      最近更新 更多