【问题标题】:How do you store an arbitrarily large integer value in memory?如何在内存中存储任意大的整数值?
【发布时间】:2011-01-16 05:02:57
【问题描述】:

我必须存储一个大于长数据类型最大值的整数值。我将如何在内存中存储和操作这个值?

如果可能,请举例说明。

【问题讨论】:

标签: c memory-management integer integer-arithmetic


【解决方案1】:

C 是一门了不起的语言,从最近几天开始,我一直在寻找在 C 中存储大值的答案。然后我终于得到了答案。 使用 unsigned long 。它通常可以存储高达 18446744073709551615 的值。 最多 20 位数字。

  #include <stdio.h>
  int main()
    {
       unsigned long x=18446744073709551615; 
       printf("%lu",x);
       return 0;
    }

【讨论】:

  • 从问题 我必须存储一个大于 long 数据类型最大值的整数值 ...您的答案最多会赢得一点。跨度>
【解决方案2】:

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】:

考虑使用这样的结构将数字存储为十进制数字序列:

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
  • 如何将两个nums 加在一起?
  • 如何将num 乘以 2?
  • 如何将num 乘以一位数?
  • 如何将num 乘以 10?
  • 如何将两个nums 相乘?提示:做一些铅笔和纸的乘法,看看它们是如何工作的。

如果您解决了这一系列问题,您应该能够为每个步骤编写一个函数,并重新使用这些函数来回答后面的问题,并最终得到一个非常简单且未经优化的 long(嗯,up to MAXDIGITdigits) 整数包,用于正数的加法和乘法。

其他问题:

  • 您如何概括 num 来表示负数和正数?
  • 如何将一个num 除以另一个(忽略余数)?这比乘法更棘手,但同样,请先用铅笔和纸做一些长除法,然后仔细考虑你要做什么。

【讨论】:

  • 一个很好的描述。之后:在该阵列上使用 base-256 而不是 base-10。 :)
  • @Kos 使用 base 2^32(或 2^64,如果在 64 位系统上)要好得多
  • @LưuVĩnhPhúc,在 C 中使用基数 2^32(或基数 2^64)可能会很尴尬,因为在添加两个“数字”后没有有效的方法来检测设置的进位位。当然,在原始汇编程序中,这种检查很容易,或者在您的 C 程序中使用内联汇编程序。但是,我怀疑这有点超出了 OP 的舒适度,至少目前是这样。
  • @DaleHagglund 没那么难。有很多用 C 编写的任意精度库。对于无符号加法,这是一个简单的比较,您可以在此站点上找到大量示例。对于带符号的加法,它有点棘手,但仍然可以使用按位运算在 1 行内实现。如果您需要速度,那就另当别论了。
  • 然而,在 2 的补码中,您可以对有符号和无符号加法/减法使用相同的过程,因此实际上非常简单。你可以在这里找到解决方案stackoverflow.com/questions/22126073/multiword-addition-in-c
【解决方案4】:
    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
    }

【讨论】:

    【解决方案5】:

    如果只是为了显示,我会建议使用 c 标准库中的 &lt;stdio.h&gt;(用于臭名昭著的 printf)或 &lt;string.h&gt; 进行一些修改。

    【讨论】:

    • 抱歉,在你解决这个问题之前,它是有史以来最令人困惑的答案的候选者。
    • 感谢您指出这一点,我应该经常重新阅读。然而,这个问题也相当令人困惑。
    【解决方案6】:

    这是大学计算机科学入门课程中的常见问题。主要关注领域是 a) 了解(整数)数字如何存储为二进制数字,以及 b) 数据结构的基础知识,如果编程语言本身不提供所需的数据结构,您可以使用 meta 或集合结构,例如 C 中的 struct、C++ 中的 class 或 Pascal 中的 record

    那么较小的整数如何存储在计算机中?在 C 中,您有数据类型char, short, int, long,它们都可以用来存储各种大小的整数。 (在此讨论中,我将忽略long long。)为了通用性,假设在给定的 32 位平台上,大小分别为 8 位、16 位、32 位和 64 位。考虑可以表示的值(以简化考虑的无符号)。

    现在,您如何存储一个无法以无符号 64 位长度存储的更大整数?制作您自己的大整数数据类型,由多个较小(但标准)的整数组成,以便它们表示较大的值。

    我认为这应该为您指明正确的方向,并使您能够为自己的家庭作业或考试问题写下自己的答案。

    【讨论】:

      【解决方案7】:

      可能的解决方案:
      1) 定义足够大以容纳该值的自定义整数类型。 128 位整数足以容纳 98474737475747374739399。
      2) 使用任何可用的bignum 库。

      【讨论】:

        【解决方案8】:

        我不会给你代码,但我可以提出一些建议:

        1. 尝试将值存储为字符串并转换以执行计算
        2. 尝试将值分解为多个整数,表示值的一部分
        3. 查找可以为您解决此问题的现有库

        祝你好运

        【讨论】:

        • 特别是如果这是为了考试,我建议您考虑一下您在小学时的数学表现。你知道,加,进 1,减,减 10 等等。如果你不能对一个字符串做这些操作,你小学不及格,因此大学计算机科学不及格。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多