diff --git a/src/main/java/com/thealgorithms/recursion/SylvesterSequence.java b/src/main/java/com/thealgorithms/recursion/SylvesterSequence.java new file mode 100644 index 000000000000..2b39f66c7936 --- /dev/null +++ b/src/main/java/com/thealgorithms/recursion/SylvesterSequence.java @@ -0,0 +1,50 @@ +package com.thealgorithms.recursion; + +import java.math.BigInteger; + +/** + * A utility class for calculating numbers in Sylvester's sequence. + * + *

Sylvester's sequence is a sequence of integers where each term is calculated + * using the formula: + *

+ * a(n) = a(n-1) * (a(n-1) - 1) + 1
+ * 
+ * with the first term being 2. + * + *

This class is final and cannot be instantiated. + * + * @see Wikipedia: Sylvester sequence + */ +public final class SylvesterSequence { + + // Private constructor to prevent instantiation + private SylvesterSequence() { + } + + /** + * Calculates the nth number in Sylvester's sequence. + * + *

The sequence is defined recursively, with the first term being 2: + *

+     * a(1) = 2
+     * a(n) = a(n-1) * (a(n-1) - 1) + 1 for n > 1
+     * 
+ * + * @param n the position in the sequence (must be greater than 0) + * @return the nth number in Sylvester's sequence + * @throws IllegalArgumentException if n is less than or equal to 0 + */ + public static BigInteger sylvester(int n) { + if (n <= 0) { + throw new IllegalArgumentException("sylvester() does not accept negative numbers or zero."); + } + if (n == 1) { + return BigInteger.valueOf(2); + } else { + BigInteger prev = sylvester(n - 1); + // Sylvester sequence formula: a(n) = a(n-1) * (a(n-1) - 1) + 1 + return prev.multiply(prev.subtract(BigInteger.ONE)).add(BigInteger.ONE); + } + } +} diff --git a/src/test/java/com/thealgorithms/recursion/SylvesterSequenceTest.java b/src/test/java/com/thealgorithms/recursion/SylvesterSequenceTest.java new file mode 100644 index 000000000000..3ea5641ac484 --- /dev/null +++ b/src/test/java/com/thealgorithms/recursion/SylvesterSequenceTest.java @@ -0,0 +1,51 @@ +package com.thealgorithms.recursion; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.math.BigInteger; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +class SylvesterSequenceTest { + + /** + * Provides test cases for valid Sylvester sequence numbers. + * Format: { n, expectedValue } + */ + static Stream validSylvesterNumbers() { + return Stream.of(new Object[] {1, BigInteger.valueOf(2)}, new Object[] {2, BigInteger.valueOf(3)}, new Object[] {3, BigInteger.valueOf(7)}, new Object[] {4, BigInteger.valueOf(43)}, new Object[] {5, BigInteger.valueOf(1807)}, new Object[] {6, new BigInteger("3263443")}, + new Object[] {7, new BigInteger("10650056950807")}, new Object[] {8, new BigInteger("113423713055421844361000443")}); + } + + @ParameterizedTest + @MethodSource("validSylvesterNumbers") + void testSylvesterValidNumbers(int n, BigInteger expected) { + assertEquals(expected, SylvesterSequence.sylvester(n), "Sylvester sequence value mismatch for n=" + n); + } + + /** + * Test edge case for n <= 0 which should throw IllegalArgumentException + */ + @ParameterizedTest + @ValueSource(ints = {0, -1, -10, -100}) + void testSylvesterInvalidZero(int n) { + assertThrows(IllegalArgumentException.class, () -> SylvesterSequence.sylvester(n)); + } + + /** + * Test a larger number to ensure no overflow occurs. + */ + @Test + void testSylvesterLargeNumber() { + int n = 10; + BigInteger result = SylvesterSequence.sylvester(n); + assertNotNull(result); + assertTrue(result.compareTo(BigInteger.ZERO) > 0, "Result should be positive"); + } +}