关于卡拉楚巴算法在c++的实现

我目前遇到的问题:我需要让用户输入两个100位的数字I1,I2,和一个基数B,运用卡拉楚巴算法让两个数字相乘得到乘积并输出。
我的卡拉楚巴算法:(a1*b1)*base^2k+[(a0+a1)(b0+b1) - a1*b1 - a0*b0]*base^k + a0*b0
        因此我多加了一个加法的方法,一个减法的方法,一个进制转换的方法,来实现卡拉楚巴算法
        我测试后发现我的加法和减法是没问题的,输出结果正确,只有karatsuba方法里有错误
我的代码:
#include 
#include 
#include 
#include 
using namespace std;

//加法:
string schoolAdd(string num1, string num2, int base) {
    string result = "";         
    int carry = 0;      

    //when I1 and I2 all empty, break the loop
    while (!num1.empty() || !num2.empty() || carry > 0) {
        int digit1 = num1.empty() ? 0 : num1.back() - '0';      // 取最后的位
        int digit2 = num2.empty() ? 0 : num2.back() - '0';
        int sum = digit1 + digit2 + carry;

        carry = sum / base;
        sum = sum % base;

        result.push_back(sum + '0');        

        if (!num1.empty()) num1.pop_back();
        if (!num2.empty()) num2.pop_back();
    }

    reverse(result.begin(), result.end());      
    return result;
}

// 转换进制
string convert(int num, int base, string result){
    if (num < base){
        return to_string(num);
    }else{
        int c = num % base;     //取余数
        num = num / base;
        result = convert(num, base, result);        
        result = result + to_string(c);
    }
    return result;
}

//减法
string substraction(string a, string b, int base)
{
    int len1 = a.length();
    int len2 = b.length();
 
  
    if (len1 < len2){
        a.insert(0, len2 - len1, '0');
    }
    else{
        b.insert(0, len1 - len2, '0');
    }
    string res;
    int carry = 0;
    for (int i = a.length() - 1; i >= 0; i--) {
        int sub = (a[i] - '0') - (b[i] - '0') - carry;
        if (sub < 0) {
            sub += base;
            carry = 1;
        }
        else {
            carry = 0;
        }
        res.insert(0, to_string(sub));
    }
    //去掉前导0
    while (res.size() > 1 && res[0] == '0'){
        res.erase(0, 1);
    }
    return res;
}


//Q2, 卡拉楚巴算法
string karatsuba(string I1, string I2, int base){
    int I1size = I1.size();
    int I2size = I2.size();
                   
    if (I1size < I2size){           //补齐位数
        for (int i = 0; i < I2size - I1size; i++){
            I1 = '0' + I1;
        }
    }else{
        for (int i = 0; i < I1size - I2size; i++){
            I2 = '0' + I2;
        }
    }
    
    if (I1.size() == 1 && I2.size() == 1){
        int num1 = I1[0] - '0';
        int num2 = I2[0] - '0';
        int product = num1 * num2;
        string result = "";
        result = convert(product, base, result);        //转换位基数base的数字
        return result;
    }else{
        //先分成两部分
        //I1
        string a1 = "";
        string a0 = "";
        int mid = I1.size() / 2;
        for (int i = 0; i < mid; i++) {
            a1 += I1[i];
        }
        for (int i = mid; i < (int)I1.size(); i++) {
            a0 += I1[i];
        }
        // I2
        string b1 = "";
        string b0 = "";
        for (int i = 0; i < mid; i++) {
            b1 += I2[i];
        }
        for (int i = mid; i < (int)I2.size(); i++) {
            b0 += I2[i];
        }
        int k = I1.size() - mid;

        // (a1*b1)*base^2k+[(a0+a1)(b0+b1) - a1*b1 - a0*b0]*base^k + a0*b0

        string a1b1 = karatsuba(a1, b1,base);       //a1*b1
        string a1a0 = schoolAdd(a1, a0, base);      //a0+a1
        string b1b0 = schoolAdd(b1, b0, base);      //b0+b1
        string a0b0 = karatsuba(a0, b0, base);       //a0*b0
        string p1 = a1b1;
        p1.insert(p1.end(), 2*k, '0');
        string p2 = karatsuba(a1a0, b1b0, base);
        string p3 = schoolAdd(a1b1, a0b0,base);
        string sub = substraction(p2, p3, base);
        sub.insert(0, k, '0');
        string p4 = a0b0;
        string result = p1;
        result = schoolAdd(result,sub,base);
        result = schoolAdd(result,p4,base);
        return result;
    }
    return "0";
}


int main() {
    int B;
    string I1, I2;

    cin >> I1 >> I2 >> B;

    cout << schoolAdd(I1, I2, B) <<" " << substraction(I1,I2, B)<<" " << karatsuba(I1,I2,B)<< endl;

    return 0;
}


我的尝试:我的输入:10000000 1 10 我的输出:10000001 9999999 000000000000001

我想要的结果应该是:10000001 9999999 10000001
请问有人知道我思路哪里错了吗

https://www.cnblogs.com/tigerisland/p/7564172.html

参考GPT和自己的思路:

经过仔细研究你的代码,我发现你在卡拉楚巴算法的实现过程中有一个小错误:在计算p2时,你应该将其乘以base^k而不是base^(2*k)

这是你的错误代码:

string p2 = karatsuba(a1a0, b1b0, base);

这是你应该修改后的正确代码:

string p2 = karatsuba(a1a0, b1b0, base);
p2.insert(p2.begin(), k, '0');

这样做的原因是,在原来的卡拉楚巴算法中,我们需要将 [(a0 + a1)(b0 + b1) - a0b0 - a1b1] 结果中的a0b0a1b1项清除,而避免使用额外的传递参数或变量,我们在这里使用了字符串拼接的方式,因此需要注意位数的保持。

所以你只需要替换代码中的部分:

// (a1*b1)*base^2k+[(a0+a1)(b0+b1) - a1*b1 - a0*b0]*base^k + a0*b0

string a1b1 = karatsuba(a1, b1,base);       //a1*b1
string a1a0 = schoolAdd(a1, a0, base);      //a0+a1
string b1b0 = schoolAdd(b1, b0, base);      //b0+b1
string a0b0 = karatsuba(a0, b0, base);       //a0*b0
string p1 = a1b1;
p1.insert(p1.end(), 2*k, '0');

string p2 = karatsuba(a1a0, b1b0, base);
string p3 = schoolAdd(a1b1, a0b0,base);

string sub = substraction(p2, p3, base);
sub.insert(0, k, '0');  // <-- Insert the k here!

string p4 = a0b0;
string result = p1;
result = schoolAdd(result,sub,base);
result = schoolAdd(result,p4,base);

return result;

我相信你会成功地运行你的程序并得到正确的答案。

https://www.cnblogs.com/tigerisland/p/7564172.html