4
4
* multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm)
5
5
* @details
6
6
* 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
8
8
* 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
10
10
* O(nlogn) of time.
11
11
* @author [Swastika Gupta](https://github.com/Swastyy)
12
+ * @author [Ameer Carlo Lubang](https://github.com/poypoyan)
12
13
*/
13
14
14
15
#include < cassert> // / for assert
@@ -24,101 +25,117 @@ namespace divide_and_conquer {
24
25
/* *
25
26
* @namespace karatsuba_algorithm
26
27
* @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
28
29
*/
29
30
namespace karatsuba_algorithm {
30
31
/* *
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
36
36
*/
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
39
39
40
+ // make the string lengths equal
40
41
int64_t len1 = first.size ();
41
42
int64_t len2 = second.size ();
42
- int64_t length = std::max (len1, len2);
43
43
std::string zero = " 0" ;
44
- if (len1 < len2) // make the string lengths equal
45
- {
44
+ if (len1 < len2) {
46
45
for (int64_t i = 0 ; i < len2 - len1; i++) {
47
46
zero += first;
48
47
first = zero;
48
+ zero = " 0" ; // Prevents CI from failing
49
49
}
50
50
} else if (len1 > len2) {
51
- zero = " 0" ;
52
51
for (int64_t i = 0 ; i < len1 - len2; i++) {
53
52
zero += second;
54
53
second = zero;
54
+ zero = " 0" ; // Prevents CI from failing
55
55
}
56
56
}
57
+
58
+ int64_t length = std::max (len1, len2);
57
59
int64_t carry = 0 ;
58
60
for (int64_t i = length - 1 ; i >= 0 ; i--) {
59
61
int64_t firstBit = first.at (i) - ' 0' ;
60
62
int64_t secondBit = second.at (i) - ' 0' ;
61
63
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);
67
66
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
70
69
}
71
70
72
71
if (carry) {
73
- result = ' 1' + result ; // adding 1 incase of overflow
72
+ result. insert (result. begin (), ' 1' ) ; // adding 1 incase of overflow
74
73
}
75
74
return result;
76
75
}
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
+
77
105
/* *
78
106
* @brief The main function implements Karatsuba's algorithm for fast
79
107
* multiplication
80
108
* @param str1 the input string 1
81
109
* @param str2 the input string 2
82
- * @returns the multiplicative number value
110
+ * @returns the product number value
83
111
*/
84
112
int64_t karatsuba_algorithm (std::string str1, std::string str2) {
85
113
int64_t len1 = str1.size ();
86
114
int64_t len2 = str2.size ();
87
115
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
+
101
117
if (n == 0 ) {
102
118
return 0 ;
103
119
}
104
120
if (n == 1 ) {
105
121
return (str1[0 ] - ' 0' ) * (str2[0 ] - ' 0' );
106
122
}
123
+
107
124
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
109
126
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
112
129
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
115
132
116
- // Calculating the three products of inputs of size n/2 recursively
133
+ // calculating the three products of inputs of size n/2 recursively
117
134
int64_t product1 = karatsuba_algorithm (Xl, Yl);
118
135
int64_t product2 = karatsuba_algorithm (Xr, Yr);
119
136
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));
122
139
123
140
return product1 * (1 << (2 * sh)) +
124
141
(product3 - product1 - product2) * (1 << sh) +
@@ -133,27 +150,27 @@ int64_t karatsuba_algorithm(std::string str1, std::string str2) {
133
150
*/
134
151
static void test () {
135
152
// 1st test
136
- std::string s11 = " 1" ;
137
- std::string s12 = " 1010" ;
153
+ std::string s11 = " 1" ; // 1
154
+ std::string s12 = " 1010" ; // 10
138
155
std::cout << " 1st test... " ;
139
156
assert (divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm (
140
- s11, s12) == 10 ); // here the multiplication is 10
157
+ s11, s12) == 10 );
141
158
std::cout << " passed" << std::endl;
142
159
143
160
// 2nd test
144
- std::string s21 = " 11" ;
145
- std::string s22 = " 1010" ;
161
+ std::string s21 = " 11" ; // 3
162
+ std::string s22 = " 1010" ; // 10
146
163
std::cout << " 2nd test... " ;
147
164
assert (divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm (
148
- s21, s22) == 30 ); // here the multiplication is 30
165
+ s21, s22) == 30 );
149
166
std::cout << " passed" << std::endl;
150
167
151
168
// 3rd test
152
- std::string s31 = " 110" ;
153
- std::string s32 = " 1010" ;
169
+ std::string s31 = " 110" ; // 6
170
+ std::string s32 = " 1010" ; // 10
154
171
std::cout << " 3rd test... " ;
155
172
assert (divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm (
156
- s31, s32) == 60 ); // here the multiplication is 60
173
+ s31, s32) == 60 );
157
174
std::cout << " passed" << std::endl;
158
175
}
159
176
0 commit comments