web-dev-qa-db-ja.com

任意の大きさの整数値をメモリにどのように格納しますか?

Longデータ型の最大値よりも大きい整数値を格納する必要があります。この値をメモリに保存して操作するにはどうすればよいですか?

可能であれば、例を通して説明してください。

10
yatin

次のような構造体を使用して、数値を10進数のシーケンスとして格納することを検討してください。

struct num {
    int ndigits;
    char d[MAXDIGITS];
};

たとえば、番号123456は次のように初期化できます。

struct num n = { 6, { 6, 5, 4, 3, 2, 1 } };

逆の桁順は、計算を簡単にするために重要であることがわかります。特に、n.d[i]の場所の値はn.d[i] * 10 ^ iです。

さて、いくつかの質問:

  • numにどのように追加しますか?
  • numに任意の1桁をどのように追加しますか?
  • 2つのnumをどのように追加しますか?
  • numに2を掛けるにはどうすればよいですか?
  • numに1桁の数字をどのように掛けますか?
  • numに10をどのように掛けますか?
  • 2つのnumをどのように乗算しますか?ヒント:鉛筆と紙の掛け算をして、それらがどのように機能するかを確認してください。

この一連の質問に取り組むと、各ステップの関数を記述し、それらの関数を再利用して後の質問に答えることができ、非常に単純で最適化されていない長い(まあ、最大- VARIABLE--桁)正の数の加算と乗算のための整数パッケージ。

その他の質問:

  • MAXDIGITを一般化して、正の数だけでなく負の数も表すにはどうすればよいですか?
  • 1つのnumを別のnumで(余りを無視して)どのように分割しますか?これは掛け算よりも難しいですが、繰り返しになりますが、鉛筆と紙の筆算を数回行うことから始めて、何をするかを慎重に考えてください。
20
Dale Hagglund

可能な解決策:
1)その値を保持するのに十分な大きさのカスタム整数型を定義します。 128ビット整数は、98474737475747374739399を保持するのに十分な大きさです。
2)利用可能な任意の bignum ライブラリを使用します。

8
SigTerm

コードは提供しませんが、取るべきアプローチについていくつか提案することができます。

  1. 値を文字列として保存し、変換して計算を実行してみてください
  2. 値を値の一部を表す複数の整数に分割してみてください
  3. あなたのためにこれを処理するかもしれない既存のライブラリを調べてください

幸運を

4

Robert Lafore-C++のオブジェクト指向プログラミング、第4版:

// verylong.cpp
// implements very long integer type
#include "verylong.h"          //header file for verylong
//--------------------------------------------------------------
void verylong::putvl() const           //display verylong
   {
   char temp[SZ];
   strcpy(temp,vlstr);                 //make copy
   cout << strrev(temp);               //reverse the copy
   }                                   //and display it
//--------------------------------------------------------------
void verylong::getvl()                 //get verylong from user
   {
   cin >> vlstr;                       //get string from user
   vlen = strlen(vlstr);               //find its length
   strrev(vlstr);                      //reverse it
   }
//--------------------------------------------------------------
verylong verylong::operator + (const verylong v) //add verylongs
   {
   char temp[SZ];
   int j;
                       //find longest number
   int maxlen = (vlen > v.vlen) ? vlen : v.vlen;
   int carry = 0;                      //set to 1 if sum >= 10
   for(j = 0; j<maxlen; j++)           //for each position
      {
      int d1 = (j > vlen-1)   ? 0 : vlstr[j]-'0';   //get digit
      int d2 = (j > v.vlen-1) ? 0 : v.vlstr[j]-'0'; //get digit
      int digitsum = d1 + d2 + carry;               //add digits
      if( digitsum >= 10 )             //if there's a carry,
         { digitsum -= 10; carry=1; }  //decrease sum by 10,
      else                             //set carry to 1
         carry = 0;                    //otherwise carry is 0
      temp[j] = digitsum+'0';          //insert char in string
      }
   if(carry==1)                        //if carry at end,
      temp[j++] = '1';                 //last digit is 1
   temp[j] = '\0';                     //terminate string
   return verylong(temp);              //return temp verylong
   }
//--------------------------------------------------------------
verylong verylong::operator * (const verylong v)  //multiply 
   {                                              //verylongs
   verylong pprod;                     //product of one digit
   verylong tempsum;                   //running total
   for(int j=0; j<v.vlen; j++)         //for each digit in arg
      {
      int digit = v.vlstr[j]-'0';      //get the digit
      pprod = multdigit(digit);        //multiply this by digit
      for(int k=0; k<j; k++)           //multiply result by
         pprod = mult10(pprod);        //   power of 10
      tempsum = tempsum + pprod;       //add product to total
      }
   return tempsum;                     //return total of prods
   }
//--------------------------------------------------------------
verylong verylong::mult10(const verylong v) const //multiply
   {                                              //arg by 10
   char temp[SZ];
   for(int j=v.vlen-1; j>=0; j--)      //move digits one 
      temp[j+1] = v.vlstr[j];          //   position higher
   temp[0] = '0';                      //put zero on low end
   temp[v.vlen+1] = '\0';              //terminate string
   return verylong(temp);              //return result
   }
//--------------------------------------------------------------
verylong verylong::multdigit(const int d2) const 
   {                                   //multiply this verylong
   char temp[SZ];                      //by digit in argument
   int j, carry = 0;
   for(j = 0; j<vlen; j++)             //for each position
      {                                //   in this verylong
      int d1 = vlstr[j]-'0';           //get digit from this
      int digitprod = d1 * d2;         //multiply by that digit
      digitprod += carry;              //add old carry
      if( digitprod >= 10 )            //if there's a new carry,
         {
         carry = digitprod/10;         //carry is high digit
         digitprod -= carry*10;        //result is low digit
         }
      else
         carry = 0;                    //otherwise carry is 0
      temp[j] = digitprod+'0';         //insert char in string
      }
   if(carry != 0)                      //if carry at end,
      temp[j++] = carry+'0';           //it's last digit
   temp[j] = '\0';                     //terminate string
   return verylong(temp);              //return verylong
   }

非常に長いクラスヘッダー

// verylong.h
// class specifier for very long integer type
#include <iostream>
#include <string.h>         //for strlen(), etc.
#include <stdlib.h>         //for ltoa()
using namespace std;

const int SZ = 1000;
        //maximum digits in verylongs

class verylong
   {
   private:
      char vlstr[SZ];       //verylong number, as a string
      int vlen;             //length of verylong string
      verylong multdigit(const int) const;   //prototypes for
      verylong mult10(const verylong) const; //private functions
   public:
      verylong() : vlen(0)             //no-arg constructor
         { vlstr[0]='\0'; }
      verylong(const char s[SZ])       //one-arg constructor
         { strcpy(vlstr, s); vlen=strlen(s); }   //for string
      verylong(const unsigned long n)  //one-arg constructor
         {                                       //for long int
         ltoa(n, vlstr, 10);           //convert to string
         strrev(vlstr);                //reverse it
         vlen=strlen(vlstr);           //find length
         }  
      void putvl() const;              //display verylong
      void getvl();                    //get verylong from user
      verylong operator + (const verylong); //add verylongs
      verylong operator * (const verylong); //multiply verylongs
   };
3
raymarch

これは、大学のコンピュータサイエンス入門クラスでよくある質問です。主な焦点は、a)(整数)数値が2桁として格納される方法を理解すること、およびb)データ構造の基本です。プログラミング言語が目的のデータ構造自体を提供しない場合は、metaまたは、Cのstruct、C++のclass、Pascalのrecordなどのコレクション構造。

では、小さい整数はどのようにコンピューターに格納されるのでしょうか。 Cには、さまざまなサイズの整数を格納するためにすべて使用できるデータ型char, short, int, longがあります。 (この説明ではlong longを無視します。)一般性のために、特定の32ビットプラットフォームでは、サイズはそれぞれ8ビット、16ビット、32ビット、および64ビットであるとしましょう。表現できる値を検討してください(符号なしと見なされるのを単純化するため)。

では、符号なし64ビット長では格納できない、より大きな整数をどのように格納できるでしょうか。大きな値を表すように、複数の小さな(ただし標準の)整数で構成される独自の大きな整数データ型を作成します。

これはあなたを正しい方向に向け、宿題や試験の質問に対するあなた自身の答えを書くことを可能にするはずだと思います。

2
mctylr
    struct digitcontainer
    {
      struct digitcontainer* left;
      struct digitcontainer* right;
      unsigned char digit;
    }

    struct longinteger
    {
      char sign;
      struct digitcontainer* firstdigit;
    }

    // positive number with 1000 digits
    void test()
    {
      struct longinteger myNumber;

      myNumber.sign = '+';
      myNumber.firstdigit = (struct digitcontainer*)malloc( sizeof(digitcontainer) );
      myNumber.firstdigit->left = NULL;
      myNumber.firstdigit->right = NULL;
      myNumber.firstdigit->digit = 1;

      struct digitcontainer* left = myNumber.firstdigit;

      for( int i=1; i<1000; i++ )
      {
        left->right = (struct digitcontainer*)malloc( sizeof( digitcontainer ) );
        left->right->left = left;
        left->right->digit = (unsigned char)i;
        left = left->right;
      }

      left->right = NULL;

      // call free for each digitcontainer you are finished using the number
    }
0