1

I have 2 strings, both contain only numbers. Those numbers are bigger than max of uint64_t.

How can I still add these 2 numbers and then convert the result to string?

NG_
  • 6,895
  • 7
  • 45
  • 67
John Smith
  • 2,291
  • 4
  • 22
  • 33
  • You could use a bignum library, or you could chop the strings up into smaller strings that fit into `uint64_t`, add them, and carry the extra digits to the next addition. – Lily Ballard Mar 13 '13 at 01:22
  • 2
    You'll need a *big-integer* library (or write your own). Time to do some Googling! – Oliver Charlesworth Mar 13 '13 at 01:22
  • The easiest approach is using a [pre-made library](http://www.boost.org/libs/multiprecision/) designed for just such things. – ildjarn Mar 13 '13 at 01:22
  • 1
    Just look up that question: http://stackoverflow.com/questions/269268/how-to-implement-big-int-in-c – Gohan Mar 13 '13 at 01:23
  • See also http://stackoverflow.com/questions/1218149/arbitrary-precision-arithmetic-explanation/1218185#1218185 for an explanation of arbitrary precision arithmetic. – paxdiablo Mar 13 '13 at 02:25

4 Answers4

6

Well, you can either use a bigger datatype (for example a library that deals with large integers), or you can quickly knock up your own.

I would suggest that if this is a one off, you do long addition exactly like you would have learned to do in your first few years of school. You can operate directly on the two strings, add the columns, do the 'carry', and build another string containing the result. You can do all this without any conversion to or from binary.

Here. Just for fun, I knocked up a solution for you:

string Add( const string& a, const string& b )
{
    // Reserve storage for the result.
    string result;
    result.reserve( 1 + std::max(a.size(), b.size()) );

    // Column positions and carry flag.
    int apos = a.size();
    int bpos = b.size();
    int carry = 0;

    // Add columns
    while( carry > 0 || apos > 0 || bpos > 0 )
    {
        if( apos > 0 ) carry += a[--apos] - '0';
        if( bpos > 0 ) carry += b[--bpos] - '0';
        result.push_back('0' + (carry%10));
        carry /= 10;
    }

    // The result string is backwards.  Reverse and return it.
    reverse( result.begin(), result.end() );
    return result;
}

Note that, for clarity, this code doesn't even attempt to handle errors. It also doesn't do negatives, but it's not hard to fix that.

paddy
  • 60,864
  • 6
  • 61
  • 103
  • Nice use of the carry for the sum as well, I've not seen it done that way before - it reduces code size nicely. – paxdiablo Mar 13 '13 at 02:09
1

You need a a BigInt implementation. You can find several different ones here.

Whatever BigInt implementation you choose, needs to have conversion to and from string (they usually do).

Jamin Grey
  • 10,151
  • 6
  • 39
  • 52
1

If you just want to handle positive numbers without having to worry about bringing in an entire bignum library like GMP (along with its tendency to just abort on out-of-memory errors, something I find unforgivable in a general purpose library), you can roll your own, something like:

static std::string add (const std::string& num1, const std::string& num2) {
    // Make num1 the wider number to simplify further code.

    int digit, idx1 = num1.length() - 1, idx2 = num2.length() - 1;
    if (idx1 < idx2) return add (num2, num1);

    // Initialise loop variables.

    int carry = 0;
    std::string res;  // reserve idx1+2 chars if you want.

    // Add digits from right until thinner number finished.

    while (idx2 >= 0) {
        digit = num1[idx1--] - '0' + num2[idx2--] - '0' + carry;
        carry = (digit > 9);
        res.insert (0, 1, (digit % 10) + '0');
    }

    // Then just process rest of wider number and any leftover carry.

    while (idx1 >= 0) {
        digit = num1[idx1--] - '0' + carry;
        carry = (digit > 9);
        res.insert (0, 1, (digit % 10) + '0');
    }
    if (carry) res.insert (0, 1, '1');

    return res;
}

You can add efficiencies like reserving space in the target string in advance, and setting specific indexes of it rather than inserting but, unless you're handling truly massive strings or doing it many time per second, I usually prefer code that is simpler to understand and maintain .

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

Here is the code for your question:

#include <iostream>
#include <string>
using namespace std;
string StrAdd(string a, string b) {
  string::reverse_iterator rit_a = a.rbegin();
  string::reverse_iterator rit_b = b.rbegin();
  string c;
  int val_c_adv = 0;
  while(rit_a != a.rend() && rit_b != b.rend() ) {
    int val_a_i = *rit_a - '0';
    int val_b_i = *rit_b - '0';
    int val_c_i = val_a_i + val_b_i + val_c_adv;
    if(val_c_i >= 10 ) {
      val_c_adv = 1;
      val_c_i -= 10;
    } else {
      val_c_adv = 0;
    }
    c.insert(0,1, (char)(val_c_i+'0'));
    ++rit_a;
    ++rit_b;
  }
  if(rit_a == a.rend() ) {
    while( rit_b != b.rend() ) {
      int val_b_i = *rit_b - '0';
      int val_c_i = val_b_i + val_c_adv;
      if(val_c_i >= 10 ) {
        val_c_adv = 1;
        val_c_i -= 10;
      } else {
        val_c_adv = 0;
      }
      c.insert(0, 1, (char)(val_c_i+'0'));
      ++rit_b;
    }
  } else if( rit_b == b.rend() ) {
    while( rit_a != a.rend() ) {
      int val_a_i = *rit_a - '0';
      int val_c_i = val_a_i + val_c_adv;
      if(val_c_i >= 10 ) {
        val_c_adv = 1;
        val_c_i -= 10;
      } else {
        val_c_adv = 0;
      }
      c.insert(0, 1, (char)(val_c_i+'0'));
      ++rit_a;
    }
  }
  return c;
}

int main() {
  string res, a, b;
  cout << "a=" << endl;
  cin >> a;
  cout << "b=" << endl;
  cin >> b;
  res = StrAdd(a, b);
  cout << "Result=" << res << endl;    
}
Kun Ling
  • 2,211
  • 14
  • 22