c++arraysstringinteger

How can I effectively store large number in integer array?


I need to build a high precision calculator that will operate with very large numbers. The whole point is that storing the values in arrays as one digit goes to separate array cell is now allowed.

That is memory representation of number 335897294593872 like so:

int number[] = {3, 3, 5, 8, 9, 7, 2, 9, 4, 5, 9, 3, 8, 7, 2};

is not legit, nor:

char number[] = {3, 3, 5, 8, 9, 7, 2, 9, 4, 5, 9, 3, 8, 7, 2};

nor:

std::string number("335897294593872");

What I want to do is to split up the whole number into 32bit chunks and store each individual chunk in separate array cell data type of which is u32int_t.

Since I get the input from keyboard I store all values in std::string initially and later put them in integer arrays to perform operations.

How do I put binary representation of a large number into an integer array filling in all bits properly?

I'm using standard C++ libraries only

I want to be able to add, subtract, multiply, divide those arrays with large numbers so I mean not to merely cut the string up and store decimal representation in integer array, but rather preserve bits order of the number itself to be able to calculate carry.


Solution

  • This is a rather naïve solution:

    1. If last digit in string is odd store a 1 in result (otherwise leave it 0).
    2. Divide digits in string by 2 (considering carries).
    3. If 32 bits have written add another element to result vector.
    4. Repeat this until string contains 0s only.

    Source Code:

    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <vector>
    #include <algorithm>
    
    std::vector<uint32_t> toBigInt(std::string text)
    {
      // convert string to BCD-like
      for (char &c : text) c -= '0';
      // build result vector
      std::vector<uint32_t> value(1, 0);
      uint32_t bit = 1;
      for (;;) {
        // set next bit if last digit is odd
        if (text.back() & 1) value.back() |= bit;
        // divide BCD-like by 2
        bool notNull = false; int carry = 0;
        for (char &c : text) {
          const int carryNew = c & 1;
          c /= 2; c += carry * 5;
          carry = carryNew;
          notNull |= c;
        }
        if (!notNull) break;
        // shift bit
        bit <<= 1;
        if (!bit) {
          value.push_back(0); bit = 1;
        }
      }
      // done
      return value;
    }
    
    std::ostream& operator<<(std::ostream &out, const std::vector<uint32_t> &value)
    {
      std::ios fmtOld(0); fmtOld.copyfmt(out);
      for (size_t i = value.size(); i--;) {
        out << std::hex << value[i] << std::setfill('0') << std::setw(sizeof (uint32_t) * 2);
      }
      out.copyfmt(fmtOld);
      return out;
    }
    
    int main()
    {
      std::string tests[] = {
        "0", "1",
        "4294967295", // 0xffffffff
        "4294967296", // 0x100000000
        "18446744073709551615", // 0xffffffffffffff
        "18446744073709551616", // 0x100000000000000
      };
      for (const std::string &test : tests) {
        std::cout << test << ": " << toBigInt(test) << '\n';
      }
      return 0;
    }
    

    Output:

    0: 0
    1: 1
    4294967295: ffffffff
    4294967296: 100000000
    18446744073709551615: ffffffffffffffff
    18446744073709551616: 10000000000000000
    

    Live Demo on coliru

    Notes:

    1. The output is little-endian. (The least significant element is first.)
    2. For the tests, I used numbers where hex-code is simple to check by eyes.