Skip to content

Commit 97c7d91

Browse files
fix: karatsuba's algorithm is not compiling (#2115)
* fix: karatsuba's algorithm is not compiling doc: improved comments * fix: continuous integration issues Co-authored-by: David Leal <[email protected]>
1 parent 84ff18e commit 97c7d91

File tree

1 file changed

+70
-53
lines changed

1 file changed

+70
-53
lines changed

divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp

+70-53
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
* multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm)
55
* @details
66
* Given two strings in binary notation we want to multiply them and return the
7-
* value Simple approach is to multiply bits one by one which will give the time
7+
* value. Simple approach is to multiply bits one by one which will give the time
88
* complexity of around O(n^2). To make it more efficient we will be using
9-
* Karatsuba' algorithm to find the product which will solve the problem
9+
* Karatsuba algorithm to find the product which will solve the problem
1010
* O(nlogn) of time.
1111
* @author [Swastika Gupta](https://github.com/Swastyy)
12+
* @author [Ameer Carlo Lubang](https://github.com/poypoyan)
1213
*/
1314

1415
#include <cassert> /// for assert
@@ -24,101 +25,117 @@ namespace divide_and_conquer {
2425
/**
2526
* @namespace karatsuba_algorithm
2627
* @brief Functions for the [Karatsuba algorithm for fast
27-
* multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm)
28+
* multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm) implementation
2829
*/
2930
namespace karatsuba_algorithm {
3031
/**
31-
* @brief Helper function for the main function, that implements Karatsuba's
32-
* algorithm for fast multiplication
33-
* @param first the input string 1
34-
* @param second the input string 2
35-
* @returns the concatenated string
32+
* @brief Binary addition
33+
* @param first, the input string 1
34+
* @param second, the input string 2
35+
* @returns the sum binary string
3636
*/
37-
std::string addStrings(std::string first, std::string second) {
38-
std::string result; // To store the resulting sum bits
37+
std::string add_strings(std::string first, std::string second) {
38+
std::string result; // to store the resulting sum bits
3939

40+
// make the string lengths equal
4041
int64_t len1 = first.size();
4142
int64_t len2 = second.size();
42-
int64_t length = std::max(len1, len2);
4343
std::string zero = "0";
44-
if (len1 < len2) // make the string lengths equal
45-
{
44+
if (len1 < len2) {
4645
for (int64_t i = 0; i < len2 - len1; i++) {
4746
zero += first;
4847
first = zero;
48+
zero = "0"; // Prevents CI from failing
4949
}
5050
} else if (len1 > len2) {
51-
zero = "0";
5251
for (int64_t i = 0; i < len1 - len2; i++) {
5352
zero += second;
5453
second = zero;
54+
zero = "0"; // Prevents CI from failing
5555
}
5656
}
57+
58+
int64_t length = std::max(len1, len2);
5759
int64_t carry = 0;
5860
for (int64_t i = length - 1; i >= 0; i--) {
5961
int64_t firstBit = first.at(i) - '0';
6062
int64_t secondBit = second.at(i) - '0';
6163

62-
int64_t sum = (firstBit ^ secondBit ^ carry) + '0'; // sum of 3 bits
63-
std::string temp;
64-
temp = std::to_string(sum);
65-
temp += result;
66-
result = temp;
64+
int64_t sum = (char(firstBit ^ secondBit ^ carry)) + '0'; // sum of 3 bits
65+
result.insert(result.begin(), sum);
6766

68-
carry = (firstBit & secondBit) | (secondBit & carry) |
69-
(firstBit & carry); // sum of 3 bits
67+
carry = char((firstBit & secondBit) | (secondBit & carry) |
68+
(firstBit & carry)); // sum of 3 bits
7069
}
7170

7271
if (carry) {
73-
result = '1' + result; // adding 1 incase of overflow
72+
result.insert(result.begin(), '1'); // adding 1 incase of overflow
7473
}
7574
return result;
7675
}
76+
77+
/**
78+
* @brief Wrapper function for substr that considers leading zeros.
79+
* @param str, the binary input string.
80+
* @param x1, the substr parameter integer 1
81+
* @param x2, the substr parameter integer 2
82+
* @param n, is the length of the "whole" string: leading zeros + str
83+
* @returns the "safe" substring for the algorithm *without* leading zeros
84+
* @returns "0" if substring spans to leading zeros only
85+
*/
86+
std::string safe_substr(const std::string &str, int64_t x1, int64_t x2, int64_t n) {
87+
int64_t len = str.size();
88+
89+
if (len >= n) {
90+
return str.substr(x1, x2);
91+
}
92+
93+
int64_t y1 = x1 - (n - len); // index in str of first char of substring of "whole" string
94+
int64_t y2 = (x1 + x2 - 1) - (n - len); // index in str of last char of substring of "whole" string
95+
96+
if (y2 < 0) {
97+
return "0";
98+
} else if (y1 < 0) {
99+
return str.substr(0, y2 + 1);
100+
} else {
101+
return str.substr(y1, x2);
102+
}
103+
}
104+
77105
/**
78106
* @brief The main function implements Karatsuba's algorithm for fast
79107
* multiplication
80108
* @param str1 the input string 1
81109
* @param str2 the input string 2
82-
* @returns the multiplicative number value
110+
* @returns the product number value
83111
*/
84112
int64_t karatsuba_algorithm(std::string str1, std::string str2) {
85113
int64_t len1 = str1.size();
86114
int64_t len2 = str2.size();
87115
int64_t n = std::max(len1, len2);
88-
std::string zero = "0";
89-
if (len1 < len2) {
90-
for (int64_t i = 0; i < len2 - len1; i++) {
91-
zero += str1;
92-
str1 = zero;
93-
}
94-
} else if (len1 > len2) {
95-
zero = "0";
96-
for (int64_t i = 0; i < len1 - len2; i++) {
97-
zero += str2;
98-
str2 = zero;
99-
}
100-
}
116+
101117
if (n == 0) {
102118
return 0;
103119
}
104120
if (n == 1) {
105121
return (str1[0] - '0') * (str2[0] - '0');
106122
}
123+
107124
int64_t fh = n / 2; // first half of string
108-
int64_t sh = (n - fh); // second half of string
125+
int64_t sh = n - fh; // second half of string
109126

110-
std::string Xl = str1.substr(0, fh); // first half of first string
111-
std::string Xr = str1.substr(fh, sh); // second half of first string
127+
std::string Xl = divide_and_conquer::karatsuba_algorithm::safe_substr(str1, 0, fh, n); // first half of first string
128+
std::string Xr = divide_and_conquer::karatsuba_algorithm::safe_substr(str1, fh, sh, n); // second half of first string
112129

113-
std::string Yl = str2.substr(0, fh); // first half of second string
114-
std::string Yr = str2.substr(fh, sh); // second half of second string
130+
std::string Yl = divide_and_conquer::karatsuba_algorithm::safe_substr(str2, 0, fh, n); // first half of second string
131+
std::string Yr = divide_and_conquer::karatsuba_algorithm::safe_substr(str2, fh, sh, n); // second half of second string
115132

116-
// Calculating the three products of inputs of size n/2 recursively
133+
// calculating the three products of inputs of size n/2 recursively
117134
int64_t product1 = karatsuba_algorithm(Xl, Yl);
118135
int64_t product2 = karatsuba_algorithm(Xr, Yr);
119136
int64_t product3 = karatsuba_algorithm(
120-
divide_and_conquer::karatsuba_algorithm::addStrings(Xl, Xr),
121-
divide_and_conquer::karatsuba_algorithm::addStrings(Yl, Yr));
137+
divide_and_conquer::karatsuba_algorithm::add_strings(Xl, Xr),
138+
divide_and_conquer::karatsuba_algorithm::add_strings(Yl, Yr));
122139

123140
return product1 * (1 << (2 * sh)) +
124141
(product3 - product1 - product2) * (1 << sh) +
@@ -133,27 +150,27 @@ int64_t karatsuba_algorithm(std::string str1, std::string str2) {
133150
*/
134151
static void test() {
135152
// 1st test
136-
std::string s11 = "1";
137-
std::string s12 = "1010";
153+
std::string s11 = "1"; // 1
154+
std::string s12 = "1010"; // 10
138155
std::cout << "1st test... ";
139156
assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm(
140-
s11, s12) == 10); // here the multiplication is 10
157+
s11, s12) == 10);
141158
std::cout << "passed" << std::endl;
142159

143160
// 2nd test
144-
std::string s21 = "11";
145-
std::string s22 = "1010";
161+
std::string s21 = "11"; // 3
162+
std::string s22 = "1010"; // 10
146163
std::cout << "2nd test... ";
147164
assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm(
148-
s21, s22) == 30); // here the multiplication is 30
165+
s21, s22) == 30);
149166
std::cout << "passed" << std::endl;
150167

151168
// 3rd test
152-
std::string s31 = "110";
153-
std::string s32 = "1010";
169+
std::string s31 = "110"; // 6
170+
std::string s32 = "1010"; // 10
154171
std::cout << "3rd test... ";
155172
assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm(
156-
s31, s32) == 60); // here the multiplication is 60
173+
s31, s32) == 60);
157174
std::cout << "passed" << std::endl;
158175
}
159176

0 commit comments

Comments
 (0)