c++ string (int) + string (int) [duplicate]

时间:2022-09-02 09:05:05

This question already has an answer here:

这个问题已经有了答案:

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

我有两个字符串,都只包含数字。这些数字大于uint64_t的最大值。

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

我怎么还能把这两个数字相加然后把结果转换成字符串呢?

4 个解决方案

#1


5  

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.

注意,为了清晰起见,此代码甚至不尝试处理错误。它也不做底片处理,但也不难修复。

#2


1  

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

您需要一个BigInt实现。你可以在这里找到几个不同的。

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

无论您选择什么BigInt实现,都需要对字符串进行转换(它们通常这样做)。

#3


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;    
}

#4


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:

如果您只是想处理正数,而不必担心引入像GMP这样的整个bignum库(以及它倾向于中止内存不足的错误,这是我在通用目的库中发现不可原谅的),那么您可以自己卷,比如:

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 .

您可以增加效率,比如预先在目标字符串中保留空间,并设置它的特定索引,而不是插入,但是,除非您正在处理大量的字符串,或者每秒执行多次,否则我通常更喜欢易于理解和维护的代码。

#1


5  

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.

注意,为了清晰起见,此代码甚至不尝试处理错误。它也不做底片处理,但也不难修复。

#2


1  

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

您需要一个BigInt实现。你可以在这里找到几个不同的。

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

无论您选择什么BigInt实现,都需要对字符串进行转换(它们通常这样做)。

#3


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;    
}

#4


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:

如果您只是想处理正数,而不必担心引入像GMP这样的整个bignum库(以及它倾向于中止内存不足的错误,这是我在通用目的库中发现不可原谅的),那么您可以自己卷,比如:

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 .

您可以增加效率,比如预先在目标字符串中保留空间,并设置它的特定索引,而不是插入,但是,除非您正在处理大量的字符串,或者每秒执行多次,否则我通常更喜欢易于理解和维护的代码。