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 */
2930namespace 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 */
84112int64_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 */
134151static 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