【问题标题】:Karatsuba Multiplication with Strings C++Karatsuba 与字符串 C++ 的乘法
【发布时间】:2021-08-23 12:40:54
【问题描述】:

我正在努力使用字符串为我的 Karatsuba 乘法获得正确的输出。 我输入的数字格式为:int1 int2 base,其中 int1 和 int2 是要相乘的数字,base 是数字底数。

我的输出格式为 add mult,其中 add 代表 int1 和 int2 的“School Method Addition”,mult 代表 Karatsuba 乘法。

对于输入:

1231000323012031333233201313312322110321130022201222133322033312000313333113222010300133031211311 10203302031023112301210030203002033323 4

我应该得到输出:

1231000323012031333233201313312322110321130022201222133322110121303011022232123220331002033311300 
490306232475117580392628428529303475424922697851904379576867313243824589283681700912220831308362948505562812188832489817917769878090

我不确定出了什么问题,任何帮助将不胜感激。

下面是我的代码:

// The main function that adds two bit sequences and returns the addition

string add_strings(string a, string b){

    string result ;  // To store the sum bits
 
    // make the lengths same before adding
    int length = max(a.length(), b.length()) ;
    while (a.length() < length) a.insert(0, "0") ;
    while (b.length() < length) b.insert(0, "0") ;

    // Initialize carry
    int carry = 0 ;
 
    // Add all bits one by one
    for (int i = length - 1 ; i > -1 ; i--)
    {
        int aBit = a[i] - '0' ;
        int bBit = b[i] - '0' ;
 
        // Boolean expression for sum of 3 bits
        int sum = aBit + bBit + carry ;

        // Update carry
        carry = sum / base ;

        // Update sum for string insertion
        sum = sum % base ;
 
        // Update sum result
        result.insert(0, to_string(sum)) ;
    }
 
    // if overflow, then add the carry
    if (carry)  result.insert(0, to_string(carry)) ;

    return result.erase(0, min(result.find_first_not_of('0'), result.size() - 1)) ;
}

// Function for find difference of larger numbers

string sub_strings(string a, string b, int base)
{
    // Ensure the first string is bigger than the second
    // Therefore no negative cases, no carry needed
    int comp = a.compare(b) ;
    if (comp < 0) swap(a, b) ;

    // Make the lengths same before subtracting
    int length = max(a.length(), b.length()) ;
    while (a.length() < length) a.insert(0, "0") ;
    while (b.length() < length) b.insert(0, "0") ;
 
    // Initialise result string
    string result = "";
    int diff, carry ;
 
    // Subtraction
    for (int i = length - 1; i > -1; i--) {
 
        // Find difference of each digit
        int aBit = a[i] - '0' ;

        int bBit = b[i] - '0' ;

        diff = (aBit - bBit) / base ;

        result.insert(0, to_string(diff)) ;
     }
 
    // reverse resultant string
    reverse(result.begin(), result.end());
 
    return result.erase(0, min(result.find_first_not_of('0'), result.size() - 1)) ; 
}

更新: 我添加了一个左移函数以确保所有内容都乘以基数:

void leftShift(string &ab, int k){

reverse(ab.begin(), ab.begin() + 1) ;
reverse(ab.begin() + 1, ab.end()) ;
reverse(ab.begin(), ab.end()) ; 

}

这是我更新的 Karatsuba:

string Karatsuba(string a, string b, int base){

// Base cases
int length = max(a.length(), b.length());
if (length == 0) return 0 ;
if (length == 1) return to_string((a[0] - '0')*(b[0] - '0')) ;

// Add leading zeros to ensure numbers are the same size
while (a.length() < length) a.insert(0, "0") ;
while (b.length() < length) b.insert(0, "0") ;

// Split a into (a0, a1) and b into (b0, b1)
int k = length / 2 ;
int upper = length - k ;

// convert the above vectors to strings for multiplication
// need separate for loops to prevent out of range errors
string a0 = a.substr(k) ;
string a1 = a.substr(0, upper) ;
string b0 = b.substr(k) ;
string b1 = b.substr(0, upper) ;

// Compute the three products
// p0 = a0b0, p1 = (a1+a0)*(b1+b0), p2 = a1b1
string p0 = Karatsuba(a0, b0, base) ;
string p1 = Karatsuba(add_strings(a1, a0, base), add_strings(b1, b0, base), base) ;
string p2 = Karatsuba(a1, b1, base) ;

//ab = p2 * (pow(base, 2*k)) + (p1 - (p2 + p0)) * pow(base, k) + p0
// term1 = p2 * (pow(base, 2*k))
// term2 = (p1 - (p2 + p0)) * pow(base, k)
string term2 = sub_strings(add_strings(p2, p0, base), p1, base) ;
leftShift(p2, k) ;
leftShift(p2, k) ;
leftShift(term2, k) ;

// term3 = p0

// Add leading zeros
for (int i = 0; i < upper; i++) p0.append("0") ;
for (int i = 0; i < upper; i++) term2.append("0") ;
    
string result = add_strings(add_strings(p2, p0, base), term2, base) ;

return result.erase(0, min(result.find_first_not_of('0'), result.size() - 1));

}

【问题讨论】:

  • c 和 c++ 是不同的语言,请不要同时标记两者,除非您实际上同时使用这两种语言。你的代码的输出是什么?您是否尝试过使用调试器?
  • 我建议您在调试阶段使用 6 字节字符串,而不是 97 字节字符串。然后您可以手动进行计算并将它们与您的代码结果进行比较。
  • 当输入为 base 4 时,为什么预期的输出不在 base 4 中?为什么你的代码有一堆 / 10% 10 表明它特定于基数 10?
  • 有很多代码需要调试和审查。我看到的第一个气味是在 floor 和 ceil 中使用浮点。 int k = length/2; 已经四舍五入了,int upper = length - k; 会给你剩下的,而不用求助于浮点数学。
  • 查看您的代码,您对base 根本没有做任何事情。

标签: c++ c++11


【解决方案1】:

首先,实现朴素加法。编写单元测试。

接下来,实现朴素乘法。编写单元测试。

接下来,实现花式乘法。您应该将验证器作为可选参数传入。用朴素的乘法验证每个子乘法。在失败博客上,什么输入会产生什么错误输出。

将其添加到单元测试用例中。

使用它来生成一个微小的错误情况,不超过 6 到 8 位。

【讨论】:

    猜你喜欢
    • 2018-10-06
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    相关资源
    最近更新 更多