2013-03-13 7 views
1

У меня есть 2 строки, оба содержат только числа. Эти цифры больше, чем максимум uint64_t.C++ string (int) + string (int)

Как я могу добавить эти 2 числа, а затем преобразовать результат в строку?

+0

Вы можете использовать bignum библиотеку, или вы можете нарезать строки на меньшие строки, которые вписываются в 'uint64_t', добавить их, и нести дополнительные цифры к следующему добавлению. –

+2

Вам понадобится библиотека * big-integer * (или напишите самостоятельно). Пора сделать что-нибудь в Google! –

+0

Самый простой подход - использование [готовой библиотеки] (http://www.boost.org/libs/multiprecision/), предназначенной только для таких вещей. – ildjarn

ответ

5

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

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

Здесь. Просто для удовольствия, я залетела для вас решение:

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

Обратите внимание, что для ясности, этот код не даже пытаться обрабатывать ошибки. Он также не делает негативов, но это не сложно исправить.

+0

Хорошее использование переноса для суммы, а также, я не видел, чтобы это делалось так раньше - это значительно уменьшает размер кода. – paxdiablo

1

Вам нужна реализация BigInt. Вы можете найти несколько разных here.

Независимо от того, какой вариант реализации BigInt вы выбрали, требуется преобразование в строку и из нее (как правило, это делается).

1

Если вы просто хотите обрабатывать положительные числа, не беспокоясь о том, чтобы собрать всю библиотеку бигмуна, такую ​​как GMP (наряду с тенденцией просто прерывать ошибки из-за памяти, что-то, что я считаю непростительным в библиотеке общего назначения), вы можете свернуть свое собственное, что-то вроде:

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

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

1

Вот код для Вашего вопроса:

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