diff --git a/src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java b/src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java new file mode 100644 index 000000000..c26e67cff --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java @@ -0,0 +1,84 @@ +package com.thealgorithms.maths; + +import java.util.List; + +/** + * @brief Implementation of the Chinese Remainder Theorem (CRT) algorithm + * @details + * The Chinese Remainder Theorem (CRT) is used to solve systems of + * simultaneous congruences. Given several pairwise coprime moduli + * and corresponding remainders, the algorithm finds the smallest + * positive solution. + */ +public final class ChineseRemainderTheorem { + private ChineseRemainderTheorem() { + } + + /** + * @brief Solves the Chinese Remainder Theorem problem. + * @param remainders The list of remainders. + * @param moduli The list of pairwise coprime moduli. + * @return The smallest positive solution that satisfies all the given congruences. + */ + public static int solveCRT(List remainders, List moduli) { + int product = 1; + int result = 0; + + // Calculate the product of all moduli + for (int mod : moduli) { + product *= mod; + } + + // Apply the formula for each congruence + for (int i = 0; i < moduli.size(); i++) { + int partialProduct = product / moduli.get(i); + int inverse = modInverse(partialProduct, moduli.get(i)); + result += remainders.get(i) * partialProduct * inverse; + } + + // Adjust result to be the smallest positive solution + result = result % product; + if (result < 0) { + result += product; + } + + return result; + } + + /** + * @brief Computes the modular inverse of a number with respect to a modulus using + * the Extended Euclidean Algorithm. + * @param a The number for which to find the inverse. + * @param m The modulus. + * @return The modular inverse of a modulo m. + */ + private static int modInverse(int a, int m) { + int m0 = m; + int x0 = 0; + int x1 = 1; + + if (m == 1) { + return 0; + } + + while (a > 1) { + int q = a / m; + int t = m; + + // m is remainder now, process same as Euclid's algorithm + m = a % m; + a = t; + t = x0; + + x0 = x1 - q * x0; + x1 = t; + } + + // Make x1 positive + if (x1 < 0) { + x1 += m0; + } + + return x1; + } +} diff --git a/src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java b/src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java new file mode 100644 index 000000000..31c676d6e --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java @@ -0,0 +1,54 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class ChineseRemainderTheoremTest { + @Test + public void testCRTSimpleCase() { + List remainders = Arrays.asList(2, 3, 2); + List moduli = Arrays.asList(3, 5, 7); + int expected = 23; + int result = ChineseRemainderTheorem.solveCRT(remainders, moduli); + assertEquals(expected, result); + } + + @Test + public void testCRTLargeModuli() { + List remainders = Arrays.asList(1, 2, 3); + List moduli = Arrays.asList(5, 7, 9); + int expected = 156; + int result = ChineseRemainderTheorem.solveCRT(remainders, moduli); + assertEquals(expected, result); + } + + @Test + public void testCRTWithSingleCongruence() { + List remainders = Arrays.asList(4); + List moduli = Arrays.asList(7); + int expected = 4; + int result = ChineseRemainderTheorem.solveCRT(remainders, moduli); + assertEquals(expected, result); + } + + @Test + public void testCRTWithMultipleSolutions() { + List remainders = Arrays.asList(0, 3); + List moduli = Arrays.asList(4, 5); + int expected = 8; + int result = ChineseRemainderTheorem.solveCRT(remainders, moduli); + assertEquals(expected, result); + } + + @Test + public void testCRTLargeNumbers() { + List remainders = Arrays.asList(0, 4, 6); + List moduli = Arrays.asList(11, 13, 17); + int expected = 550; + int result = ChineseRemainderTheorem.solveCRT(remainders, moduli); + assertEquals(expected, result); + } +}