アプリ版:「スタンプのみでお礼する」機能のリリースについて

C言語で最大計算結果が30桁の計算をしたいのですが、どのようにやったらよいのでしょうか?

long型で表現できる数を繰り返し、足していき、結果を最大30桁まで表示したいのですが、便利な関数ありますか?また、自作関数で便利な方法がありますか?

A 回答 (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
    • good
    • 0

この程度であれば、あまり高機能な多倍長演算でなくても、桁上がりだけ処理してやれば十分な気がします。


つまり、

1. 下位ワードの加算
2. 桁上がりがあれば、上位ワードをインクリメント
3. 2.を必要なワード数繰り返す

後は、加算する数が負の場合のことを考えて、もう一ひねりすれば完成です。
ちなみに、8ビットのCPUで16ビットや32ビットの加算を行うときは、大抵このようなことをアセンブリ言語で記述します。

ただ、加算はこれで構いませんが、結果の表示を10進数で行うのであれば、そのときに除算が必要になります。
除算は面倒なので、はじめから各ワードが0~999999の範囲を表現するなどにしておいた方がよいでしょう。
(各ワードが6桁ずつなら、3桁ずつ区切って出力するのも簡単なので)
    • good
    • 0

多倍長計算でやれば、理論的には何桁でもできます。


「多倍長計算」でネット検索すると、色々な解説が見つかるはずです。
一例
http://na-inet.jp/nasoft/chap04.pdf
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!