Как вы храните произвольно большое целочисленное значение в памяти?

Мне нужно сохранить целочисленное значение, превышающее максимальное значение для длинного типа данных. Как мне хранить это значение в памяти и управлять им?

Пожалуйста, проиллюстрируйте это на примере, если это возможно.


person yatin    schedule 12.02.2010    source источник
comment
gmplib.org   -  person ziya    schedule 12.02.2010


Ответы (7)


Подумайте о хранении чисел в виде последовательностей десятичных цифр с использованием такой структуры:

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?
  • Как бы вы сложили два num вместе?
  • Как бы вы умножили num на два?
  • Как бы вы умножили num на одну цифру?
  • Как бы вы умножили num на 10?
  • Как бы вы перемножили два num вместе? СОВЕТ: сделайте несколько умножений карандашом и бумагой и посмотрите, как они работают.

Если вы проработаете эту последовательность вопросов, вы сможете написать функцию для каждого шага и повторно использовать эти функции, чтобы ответить на более поздние вопросы, и в итоге получить очень простой и неоптимизированный длинный (ну, до MAXDIGIT цифр) ) целочисленный пакет для сложения и умножения положительных чисел.

Другие вопросы:

  • Как вы обобщаете num для представления как положительных, так и отрицательных чисел?
  • Как разделить одно num на другое (без учета остатка)? Это сложнее, чем умножение, но опять же, начните с нескольких делений карандашом и бумагой и тщательно обдумайте, что вы делаете.
person Dale Hagglund    schedule 13.02.2010
comment
Хорошее описание. И после этого: используйте base-256 вместо base-10 в этом массиве. :) - person Kos; 18.11.2010
comment
@Kos, использующий базу 2 ^ 32 (или 2 ^ 64 в 64-битных системах), намного лучше - person phuclv; 18.06.2014
comment
@LưuVĩnhPhúc, работа с основанием 2 ^ 32 (или основанием 2 ^ 64) может быть неудобной в C, потому что нет эффективного способа определить, какой бит переноса устанавливается после добавления двух цифр. В сыром ассемблере эта проверка, конечно, была бы легкой, или с встроенным ассемблером в вашу программу на C. Тем не менее, я подозреваю, что это немного выходит за рамки того, где ОП было бы удобно, по крайней мере, на данный момент. - person Dale Hagglund; 01.08.2014
comment
@DaleHagglund Это не так уж и сложно. Существует множество библиотек произвольной точности, написанных на C. Для сложения без знака это простое сравнение, вы можете найти множество примеров этого на этом сайте. Для добавления со знаком это немного сложнее, но все же может быть достигнуто в пределах 1 строки с использованием побитовых операций. Если вам нужна скорость, это другое дело. - person phuclv; 01.08.2014
comment
однако в дополнении 2 вы можете использовать одну и ту же процедуру как для знакового, так и для беззнакового сложения/вычитания, так что на самом деле это очень просто. Вы можете найти решения здесь stackoverflow.com/questions/22126073/multiword- дополнение-в-с - person phuclv; 01.08.2014
comment
несколько примеров для эффективного получения флага переноса в C /stackoverflow.com/q/6659414/995714"> stackoverflow.com/q/6659414/995714 - person phuclv; 10.12.2016

Возможные решения:
1) Определите собственный целочисленный тип, достаточно большой для хранения этого значения. 128-битное целое число достаточно велико, чтобы вместить 98474737475747374739399.
2) Используйте любую доступную библиотеку bignum. .

person SigTerm    schedule 12.02.2010

Я не буду давать вам код, но могу предложить пару подходов:

  1. Попробуйте сохранить значение в виде строки символов и преобразовать его для выполнения вычислений.
  2. Попробуйте разбить значение на несколько целых чисел, представляющих часть значения.
  3. Найдите существующие библиотеки, которые могут позаботиться об этом за вас.

Удачи

person Amish Programmer    schedule 12.02.2010
comment
В частности, если это для экзамена, я бы порекомендовал вам подумать о том, как вы выполняли математику в начальной школе. Вы знаете, сложите, перенесите 1, вычтите, уберите 10 и т. д. Если вы не можете выполнять эти операции над строкой символов, вы не прошли начальную школу и, следовательно, не прошли информатику в университете. - person PP.; 12.02.2010

Роберт Лафор - Объектно-ориентированное программирование на 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

// 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
   };
person raymarch    schedule 11.05.2012
comment
Такого хранения десятичных цифр может быть достаточно для экзамена, но в реальных вычислениях это будет неэффективно. Библиотеки Bigint вместо этого используют цифры по основанию 2^64 (или по основанию 2^32 на 32-разрядном компьютере) - person phuclv; 10.12.2016

Это распространенный вопрос на вводных занятиях по информатике в университете. Основное внимание уделяется а) пониманию того, как (целые) числа хранятся в виде двоичных цифр, и б) основам структур данных, где, если язык программирования сам по себе не предоставляет желаемую структуру данных, вы можете использовать meta. или структуры коллекций, например struct в C, class в C++ или record в Pascal.

Итак, как меньшее целое число хранится в компьютере? В C у вас есть типы данных char, short, int, long, которые можно использовать для хранения целых чисел различных размеров. (Я проигнорирую long long в этом обсуждении.) Скажем для общности, что на данной 32-битной платформе размеры 8-битные, 16-битные, 32-битные и 64-битные соответственно. Рассмотрим значения, которые могут быть представлены (для упрощения считаются беззнаковыми).

Теперь, как вы можете сохранить большее целое число, которое не может быть сохранено в беззнаковом 64-битном длинном? Создайте свой собственный тип данных больших целых чисел, состоящий из нескольких меньших (но стандартных) целых чисел, чтобы они представляли большие значения.

Я думаю, что это должно указать вам правильное направление и позволить вам написать свой собственный ответ на домашнее задание или экзаменационный вопрос.

person Community    schedule 13.02.2010

Если это только для отображения, я бы предложил <stdio.h> (для печально известного printf) из стандартной библиотеки c или, возможно, <string.h>, чтобы внести некоторые изменения.

person call me Steve    schedule 13.02.2010
comment
Извините, но пока вы не исправите это, это кандидат на самый запутанный ответ. - person Bill Forster; 13.02.2010
comment
Спасибо за указание на это, я должен всегда перечитывать. Однако вопрос тоже довольно запутанный. - person call me Steve; 13.02.2010

C - удивительный язык, последние несколько дней я искал ответ для хранения больших значений в C. Затем я наконец получил ответ. используйте unsigned long. Обычно он может хранить значение до 18446744073709551615. Это число может содержать до 20 цифр.

  #include <stdio.h>
  int main()
    {
       unsigned long x=18446744073709551615; 
       printf("%lu",x);
       return 0;
    }
person Ayush Kapri    schedule 08.06.2019
comment
Из вопроса Я должен сохранить целочисленное значение, которое больше, чем максимальное значение для длинного типа данных... ваш ответ в лучшем случае выигрывает один бит. - person rene; 08.06.2019