Skip to content

Commit 83a4288

Browse files
saahil-mahatoalxkm
authored andcommitted
feat: add karatsuba multiplication (TheAlgorithms#5719)
* feat: add karatsuba multiplication * fix: fallback size * fix: big integer instances --------- Co-authored-by: Alex Klymenko <[email protected]>
1 parent 1818763 commit 83a4288

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.thealgorithms.maths;
2+
3+
import java.math.BigInteger;
4+
5+
/**
6+
* This class provides an implementation of the Karatsuba multiplication algorithm.
7+
*
8+
* <p>
9+
* Karatsuba multiplication is a divide-and-conquer algorithm for multiplying two large
10+
* numbers. It is faster than the classical multiplication algorithm and reduces the
11+
* time complexity to O(n^1.585) by breaking the multiplication of two n-digit numbers
12+
* into three multiplications of n/2-digit numbers.
13+
* </p>
14+
*
15+
* <p>
16+
* The main idea of the Karatsuba algorithm is based on the following observation:
17+
* </p>
18+
*
19+
* <pre>
20+
* Let x and y be two numbers:
21+
* x = a * 10^m + b
22+
* y = c * 10^m + d
23+
*
24+
* Then, the product of x and y can be expressed as:
25+
* x * y = (a * c) * 10^(2*m) + ((a * d) + (b * c)) * 10^m + (b * d)
26+
* </pre>
27+
*
28+
* The Karatsuba algorithm calculates this more efficiently by reducing the number of
29+
* multiplications from four to three by using the identity:
30+
*
31+
* <pre>
32+
* (a + b)(c + d) = ac + ad + bc + bd
33+
* </pre>
34+
*
35+
* <p>
36+
* The recursion continues until the numbers are small enough to multiply directly using
37+
* the traditional method.
38+
* </p>
39+
*/
40+
public final class KaratsubaMultiplication {
41+
42+
/**
43+
* Private constructor to hide the implicit public constructor
44+
*/
45+
private KaratsubaMultiplication() {
46+
}
47+
48+
/**
49+
* Multiplies two large numbers using the Karatsuba algorithm.
50+
*
51+
* <p>
52+
* This method recursively splits the numbers into smaller parts until they are
53+
* small enough to be multiplied directly using the traditional method.
54+
* </p>
55+
*
56+
* @param x The first large number to be multiplied (BigInteger).
57+
* @param y The second large number to be multiplied (BigInteger).
58+
* @return The product of the two numbers (BigInteger).
59+
*/
60+
public static BigInteger karatsuba(BigInteger x, BigInteger y) {
61+
// Base case: when numbers are small enough, use direct multiplication
62+
// If the number is 4 bits or smaller, switch to the classical method
63+
if (x.bitLength() <= 4 || y.bitLength() <= 4) {
64+
return x.multiply(y);
65+
}
66+
67+
// Find the maximum bit length of the two numbers
68+
int n = Math.max(x.bitLength(), y.bitLength());
69+
70+
// Split the numbers in the middle
71+
int m = n / 2;
72+
73+
// High and low parts of the first number x (x = a * 10^m + b)
74+
BigInteger high1 = x.shiftRight(m); // a = x / 2^m (higher part)
75+
BigInteger low1 = x.subtract(high1.shiftLeft(m)); // b = x - a * 2^m (lower part)
76+
77+
// High and low parts of the second number y (y = c * 10^m + d)
78+
BigInteger high2 = y.shiftRight(m); // c = y / 2^m (higher part)
79+
BigInteger low2 = y.subtract(high2.shiftLeft(m)); // d = y - c * 2^m (lower part)
80+
81+
// Recursively calculate three products
82+
BigInteger z0 = karatsuba(low1, low2); // z0 = b * d (low1 * low2)
83+
BigInteger z1 = karatsuba(low1.add(high1), low2.add(high2)); // z1 = (a + b) * (c + d)
84+
BigInteger z2 = karatsuba(high1, high2); // z2 = a * c (high1 * high2)
85+
86+
// Combine the results using Karatsuba's formula
87+
// z0 + ((z1 - z2 - z0) << m) + (z2 << 2m)
88+
return z2
89+
.shiftLeft(2 * m) // z2 * 10^(2*m)
90+
.add(z1.subtract(z2).subtract(z0).shiftLeft(m)) // (z1 - z2 - z0) * 10^m
91+
.add(z0); // z0
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.thealgorithms.maths;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.math.BigInteger;
6+
import java.util.stream.Stream;
7+
import org.junit.jupiter.params.ParameterizedTest;
8+
import org.junit.jupiter.params.provider.Arguments;
9+
import org.junit.jupiter.params.provider.MethodSource;
10+
11+
/**
12+
* Unit test class for {@link KaratsubaMultiplication} class.
13+
*
14+
* <p>
15+
* This class tests various edge cases and normal cases for the
16+
* Karatsuba multiplication algorithm implemented in the KaratsubaMultiplication class.
17+
* It uses parameterized tests to handle multiple test cases.
18+
* </p>
19+
*/
20+
class KaratsubaMultiplicationTest {
21+
22+
/**
23+
* Provides test data for the parameterized test.
24+
* Each entry in the stream contains three elements: x, y, and the expected result.
25+
*
26+
* @return a stream of arguments for the parameterized test
27+
*/
28+
static Stream<Arguments> provideTestCases() {
29+
return Stream.of(
30+
// Test case 1: Two small numbers
31+
Arguments.of(new BigInteger("1234"), new BigInteger("5678"), new BigInteger("7006652")),
32+
// Test case 2: Two large numbers
33+
Arguments.of(new BigInteger("342364"), new BigInteger("393958"), new BigInteger("134877036712")),
34+
// Test case 3: One number is zero
35+
Arguments.of(BigInteger.ZERO, new BigInteger("5678"), BigInteger.ZERO),
36+
// Test case 4: Both numbers are zero
37+
Arguments.of(BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO),
38+
// Test case 5: Single-digit numbers
39+
Arguments.of(new BigInteger("9"), new BigInteger("8"), new BigInteger("72")));
40+
}
41+
42+
/**
43+
* Parameterized test for Karatsuba multiplication.
44+
*
45+
* <p>
46+
* This method runs the Karatsuba multiplication algorithm for multiple test cases.
47+
* </p>
48+
*
49+
* @param x the first number to multiply
50+
* @param y the second number to multiply
51+
* @param expected the expected result of x * y
52+
*/
53+
@ParameterizedTest
54+
@MethodSource("provideTestCases")
55+
void testKaratsubaMultiplication(BigInteger x, BigInteger y, BigInteger expected) {
56+
assertEquals(expected, KaratsubaMultiplication.karatsuba(x, y));
57+
}
58+
}

0 commit comments

Comments
 (0)