web-dev-qa-db-ja.com

Cが最初の100万フィボナッチ数を出力

最初の100万フィボナッチ数を出力するCコードを記述しようとしています。

実際の問題はlats 10 digits of F(1,000,000)を取得したいです。

シーケンスがどのように機能するか、それを実現するためのコードの記述方法を理解していますが、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)を印刷する可能性があまりないため、最初の100万を印刷しようとしませんでした。

7
Chris Edwards

Fib(1000000)の最後の10桁が必要です。 フィボナッチ数 についてもっと読んでください(そしてtwiceを読んでください)。

あまり考えなくても、 GMPlib のような bignum ライブラリを使用できます。 fewmpz_t bigint変数を使用してループしてFib(1000000)を計算します(100万のmpz_tの配列は必要ありませんが、手の中に指がある場合よりも少ないmpz_t変数)。もちろん、すべてのフィボナッチ数を印刷するのではなく、最後の1000000だけを印刷します番目 1つ(したがって、今日の安価なラップトップには十分なメモリがあり、1時間以内にその数を吐き出します)。 John Colemanが回答 約200K桁(つまり、それぞれ80桁の2500行)。

(ところで、いくつかの大きな出力を生成するプログラムについて考えるときは、その出力の通常のサイズとそれを取得するための通常の時間をより正確に推測します。デスクトップルームまたはデスクトップコンピューターに収まらない場合は、あなたは問題を抱えています、おそらく経済的な問題です:より多くのコンピューティングリソースを購入する必要があります)

効率的なbignum演算は難しい課題です。 bignum演算用の巧妙なアルゴリズムが存在しますが、これは、想像している単純なアルゴリズムよりもはるかに効率的です。

実際には、bigintは必要ありません。 モジュラー演算 についての数学の教科書を読んでください。和(または積)の係数は、係数の和(または積)に合同です。そのプロパティを使用します。 10桁の整数は64ビットint64_tに収まるため、bignumライブラリは必要ないと考える人もいます。

(少し考えれば、計算にコンピュータやCプログラムは必要ないでしょう。安価な計算機、鉛筆、紙で十分です。おそらく計算機はまったく必要ありません。)

プログラミング時(または数学の演習を解くとき)に学ぶべき教訓は、問題について考えることおよび再定式化することですコーディングを開始する前の質問。 J.Pitrat(フランスで人工知能のパイオニア、現在は引退しましたが、まだ彼のコンピューターで作業しています)には、それに関連するいくつかの興味深い blog エントリーがあります: 問題を定義することは可能ですか?ドナルドとジェラルドがロバートに会ったとき など.

問題(およびサブ問題も!)を理解して考えることは、ソフトウェア開発の興味深い部分です。ソフトウェア開発に取り組む場合、最初に実際の問題を解決するように求められ(たとえば、販売用のWebサイトや自律型掃除機を作る)、その問題をコード化可能なものに変換することを考える必要があります。コンピューター。我慢してください、あなたは プログラミングを学ぶのに10年 を必要とするでしょう。

「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桁をxにして、最終的な回答を提供しない)

 66843xxxxx

ビネットの公式 n番目のフィボナッチ数は、ほぼ黄金比(約1.618)をn乗して5の平方根で除算したものです。単純に対数を使用すると、100万番目のフィボナッチ数が200,000桁以上。したがって、最初の100万フィボナッチ数のうちの1つの平均長は、100,000 = 10 ^ 5を超えます。したがって、10 ^ 11 = 1,000億桁を印刷しようとしています。そのためには、大きなintライブラリー以上のものが必要になると思います。

一方、100万番目の数値を単純に計算したい場合は、そうすることができます。ただし、すべての中間数を計算しない方法を使用する方が良いでしょう(すべてを印刷するのではなく単に計算するように)十分な大きさのn)にはまだ実行不可能です。 n番目のフィボナッチ数が行列[[1,1],[1,0]]のn乗の4エントリの1つであることはよく知られています( this を参照)。 指数による二乗 (行列の乗算は連想であるため、行列のべき乗でも機能します)を優れた大きな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万番目のフィボナッチ数列を呼び出すことに注意してください。最初のフィボナッチ数列として1から始めるのが標準的です(そして、フィボナッチ数列として数えたい場合は0を0と呼びます)。最初の出力番号は、番号に200,000桁以上あることを確認し、2番目の出力は最後の10桁を示します(これはもはや謎ではありません)。最後の数字は、グーゴルスのフィボナッチ数列の最後の100桁です。ほんの一瞬で計算されます。私はまだgoogolplexを行うことができません:)

4
John Coleman

この質問は間違いなくプログラミングの競争から来ているので、これらの質問を注意深く読む必要があります。

100万番目のフィボナッチ数は巨大です。おそらく20万桁くらいでしょうか。最初の1,000,000フィボナッチ数を印刷すると、木の森全体が死んでしまいます。しかし、注意深く読んでください。100万番目のフィボナッチ数を求める人はいません。その番号の最後の10桁を尋ねられます。

したがって、Fib(n-2)とFib(n-1)の最後の10桁がある場合、どうすればFib(n)の最後の10桁を見つけることができますか?数値自体を計算せずにフィボナッチ数列の最後の10桁をどのように計算しますか?

PS。 %dを使用して長い数字を印刷することはできません。 %lldを使用します。

3
gnasher729

あなたのアルゴリズムは実際に正しいです。 unsigned long longを使用しているため、最後の10桁をキャプチャするのに十分な桁数があり、符号なしオーバーフロー関数の性質をモジュロ演算として使用できるため、少なくとも最後の10桁で正しい結果が得られます。

問題は、出力に使用している形式指定子にあります。

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

%d書式指定子はintを想定していますが、unsigned long longを渡しています。誤ったフォーマット指定子を使用すると、 未定義の動作 が呼び出されます。

この特定のケースで最も可能性が高いのは、printfnextの下位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
1
dbush