• ベストアンサー

計算結果がlong型以上になる場合の計算方法。(足し算)

C言語で最大計算結果が30桁の計算をしたいのですが、どのようにやったらよいのでしょうか? long型で表現できる数を繰り返し、足していき、結果を最大30桁まで表示したいのですが、便利な関数ありますか?また、自作関数で便利な方法がありますか?

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★アドバイス ・次のリンクの『多倍長整数演算ライブラリ』の項目を参考に簡単な30桁の四則演算を作成してみて下さい。  http://www5.airnet.ne.jp/tomy/cpro/csource.htm→『技術計算用Cプログラム ソース』 ・long long 型が使えるのならば1つの要素を long 型で 1000,000,000 進法で表現して乗算、除算の  ときに long long 型を使います。もし、long long 型が使えない環境なら1つの要素は short 型の  10,000 進法を使います。この場合は乗算、除算では long 型になります。 ・構造体は  typedef struct {   int sin; ←符号(-1,0,+1)   int len; ←num の有効数   long num[ 4 + 1 ]; ←多倍長整数の要素配列  } longint_t;  ↑  これを参考に四則演算の関数群を用意してみる。  1要素が long 型なので 9桁×4要素=36桁まで計算可能。 サンプル: // 1要素のベース値 #define BASE_VALUE (1000000000L) // 絶対値の加算 void abs_add( long ans[], long a[], long b[], int len ) {  int i, carry = 0;    for ( i = 0 ; i < len ; i++ ){   if ( (ans[i] = (a[i] + b[i] + carry)) >= BASE_VALUE ){    ans[ i ] -= BASE_VALUE;    carry = 1;   }   else{    carry = 0;   }  } } // 絶対値の減算(必ず大きい数から小さい数を引くこと) void abs_sub( long ans[], long a[], long b[], int len ) {  int i, borrow = 0;    for ( i = 0 ; i < len ; i++ ){   if ( (ans[i] = (a[i] - b[i] - borrow)) >= BASE_VALUE ){    ans[ i ] += BASE_VALUE;    borrow = 1;   }   else{    borrow = 0;   }  } } // 絶対値の比較(-1:a<b, 0:a=b, +1:a>b) int abs_cmp( long a[], long b[], int len ) {  while ( --len >= 0 ){   if ( a[len] != b[len] ){    return (a[len] < b[len]) ? -1 : +1; // 大小値   }  }  return 0; // 一致 } // 多倍長整数の加算(符号対応) longint_t add( longint_t a, longint_t b ) {  longint_t ans = { 0 };    if ( a.sin == b.sin ){ // 符号が同じ   abs_add( ans.num, a.num, b.num, ans.len );   ans.sin = a.sin;  }  if ( abs_cmp(a,b) > 0 ){ // a が大きい   abs_sub( ans.num, a.num, b.num, ans.len );   ans.sin = a.sin;  }  else{ // b が大きい   abs_sub( ans.num, b.num, a.num, ans.len );   ans.sin = b.sin;  }  return ans; } // 多倍長整数の減算(符号対応) longint_t add( longint_t a, longint_t b ) {  longint_t ans = { 0 };    if ( a.sin != b.sin ){ // 符号が異なる   abs_add( ans.num, a.num, b.num, ans.len );   ans.sin = a.sin;  }  if ( abs_cmp(a,b) > 0 ){ // a が大きい   abs_sub( ans.num, a.num, b.num, ans.len );   ans.sin = a.sin;  }  else{ // b が大きい   abs_sub( ans.num, b.num, a.num, ans.len );   ans.sin = b.sin;  }  return ans; } 最後に: ・配列の[0]を一番小さい桁の要素として計算しています。  つまり、111111111222222222333333333444444444 という数値は  num[0]⇒444444444  num[1]⇒333333333  num[2]⇒222222222  num[3]⇒111111111  num[4]⇒オーバーフロー用  となります。 ・サンプルではオーバーフローのチェックは付けていません。  上位関数などでチェックして下さい。 ・残りの乗算、除算、剰余、その他はご自分で作成してみて下さい。  文字列への変換は 10 進数なら簡単に sprintf() 関数で出来ます。 ・以上。参考に!

参考URL:
http://www5.airnet.ne.jp/tomy/cpro/csource.htm

その他の回答 (2)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

この程度であれば、あまり高機能な多倍長演算でなくても、桁上がりだけ処理してやれば十分な気がします。 つまり、 1. 下位ワードの加算 2. 桁上がりがあれば、上位ワードをインクリメント 3. 2.を必要なワード数繰り返す 後は、加算する数が負の場合のことを考えて、もう一ひねりすれば完成です。 ちなみに、8ビットのCPUで16ビットや32ビットの加算を行うときは、大抵このようなことをアセンブリ言語で記述します。 ただ、加算はこれで構いませんが、結果の表示を10進数で行うのであれば、そのときに除算が必要になります。 除算は面倒なので、はじめから各ワードが0~999999の範囲を表現するなどにしておいた方がよいでしょう。 (各ワードが6桁ずつなら、3桁ずつ区切って出力するのも簡単なので)

noname#182251
noname#182251
回答No.1

多倍長計算でやれば、理論的には何桁でもできます。 「多倍長計算」でネット検索すると、色々な解説が見つかるはずです。 一例 http://na-inet.jp/nasoft/chap04.pdf

関連するQ&A