From f8453830a7eba4a592b8656c7136ec4d6670300e Mon Sep 17 00:00:00 2001 From: MandarGharse Date: Mon, 14 Oct 2024 21:56:52 +0300 Subject: [PATCH] #7430 : Implement MultiFactorial methods --- .../common/math/BigIntegerMathTest.java | 27 ++++++++++++++++++ .../com/google/common/math/IntMathTest.java | 27 ++++++++++++++++++ .../com/google/common/math/LongMathTest.java | 27 ++++++++++++++++++ .../common/math/BigIntegerMathTest.java | 28 +++++++++++++++++++ .../com/google/common/math/IntMathTest.java | 28 +++++++++++++++++++ .../com/google/common/math/LongMathTest.java | 28 +++++++++++++++++++ .../google/common/math/BigIntegerMath.java | 24 ++++++++++++++++ guava/src/com/google/common/math/IntMath.java | 24 ++++++++++++++++ .../src/com/google/common/math/LongMath.java | 25 ++++++++++++++++- 9 files changed, 237 insertions(+), 1 deletion(-) diff --git a/android/guava-tests/test/com/google/common/math/BigIntegerMathTest.java b/android/guava-tests/test/com/google/common/math/BigIntegerMathTest.java index 36dcbf6942ad..d657573241c5 100644 --- a/android/guava-tests/test/com/google/common/math/BigIntegerMathTest.java +++ b/android/guava-tests/test/com/google/common/math/BigIntegerMathTest.java @@ -790,6 +790,33 @@ public void testNullPointers() { tester.testAllPublicStaticMethods(BigIntegerMath.class); } + public void testMultifactorialBasic() { + assertEquals(BigInteger.valueOf(105), BigIntegerMath.multiFactorial(7, 2)); // 7 * 5 * 3 * 1 + assertEquals(BigInteger.valueOf(28), BigIntegerMath.multiFactorial(7, 3)); // 7 * 4 * 1 + assertEquals(BigInteger.ONE, BigIntegerMath.multiFactorial(0, 1)); // Base case + assertEquals(BigInteger.ONE, BigIntegerMath.multiFactorial(1, 1)); // 1! + } + + public void testMultifactorialWithIncrementOne() { + assertEquals(BigInteger.valueOf(120), BigIntegerMath.multiFactorial(5, 1)); // 5 * 4 * 3 * 2 * 1 + } + + public void testMultifactorialNegativeIncrement() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + BigIntegerMath.multiFactorial(5, -1); + }); + assertEquals("Step value k must be a positive integer.", exception.getMessage()); + } + + public void testMultifactorialWithLargeNumber() { + assertEquals(new BigInteger("3628800"), BigIntegerMath.multiFactorial(10, 1)); + } + + public void testMultifactorialWithLargeInput() { + BigInteger result = BigIntegerMath.multiFactorial(100, 10); + assertTrue(result.compareTo(BigInteger.ZERO) > 0); // Result should be positive + } + @GwtIncompatible // String.format private static void failFormat(String template, Object... args) { fail(String.format(template, args)); diff --git a/android/guava-tests/test/com/google/common/math/IntMathTest.java b/android/guava-tests/test/com/google/common/math/IntMathTest.java index 73128e46803f..d8e195719544 100644 --- a/android/guava-tests/test/com/google/common/math/IntMathTest.java +++ b/android/guava-tests/test/com/google/common/math/IntMathTest.java @@ -771,6 +771,33 @@ public void testIsPrime() { } } + public void testMultifactorialBasic() { + assertEquals(105, IntMath.multiFactorial(7, 2)); // 7 * 5 * 3 * 1 + assertEquals(28, IntMath.multiFactorial(7, 3)); // 7 * 4 * 1 + assertEquals(1, IntMath.multiFactorial(0, 1)); // Base case + assertEquals(1, IntMath.multiFactorial(1, 1)); // 1! + } + + public void testMultifactorialWithIncrementOne() { + assertEquals(120, IntMath.multiFactorial(5, 1)); // 5 * 4 * 3 * 2 * 1 + } + + public void testMultifactorialNegativeIncrement() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + IntMath.multiFactorial(5, -1); + }); + assertEquals("Step value k must be a positive integer.", exception.getMessage()); + } + + public void testMultifactorialWithLargeNumber() { + assertEquals(3628800, IntMath.multiFactorial(10, 1)); + } + + public void testMultifactorialWithLargeInput() { + int result = IntMath.multiFactorial(100, 10); + assertTrue(result > 0); // Result should be positive + } + private static int force32(int value) { // GWT doesn't consistently overflow values to make them 32-bit, so we need to force it. return value & 0xffffffff; diff --git a/android/guava-tests/test/com/google/common/math/LongMathTest.java b/android/guava-tests/test/com/google/common/math/LongMathTest.java index e5598c68792d..3eb8f4646818 100644 --- a/android/guava-tests/test/com/google/common/math/LongMathTest.java +++ b/android/guava-tests/test/com/google/common/math/LongMathTest.java @@ -1025,6 +1025,33 @@ public void testRoundToDoubleAgainstBigIntegerUnnecessary() { } } + public void testMultifactorialBasic() { + assertEquals(105l, LongMath.multiFactorial(7, 2)); // 7 * 5 * 3 * 1 + assertEquals(28l, LongMath.multiFactorial(7, 3)); // 7 * 4 * 1 + assertEquals(1l, LongMath.multiFactorial(0, 1)); // Base case + assertEquals(1l, LongMath.multiFactorial(1, 1)); // 1! + } + + public void testMultifactorialWithIncrementOne() { + assertEquals(120l, LongMath.multiFactorial(5, 1)); // 5 * 4 * 3 * 2 * 1 + } + + public void testMultifactorialNegativeIncrement() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + LongMath.multiFactorial(5, -1); + }); + assertEquals("Step value k must be a positive integer.", exception.getMessage()); + } + + public void testMultifactorialWithLargeNumber() { + assertEquals(3628800l, LongMath.multiFactorial(10, 1)); + } + + public void testMultifactorialWithLargeInput() { + long result = LongMath.multiFactorial(100, 10); + assertTrue(result > 0l); // Result should be positive + } + private static void failFormat(String template, Object... args) { assertWithMessage(template, args).fail(); } diff --git a/guava-tests/test/com/google/common/math/BigIntegerMathTest.java b/guava-tests/test/com/google/common/math/BigIntegerMathTest.java index 36dcbf6942ad..e95fb1f43f16 100644 --- a/guava-tests/test/com/google/common/math/BigIntegerMathTest.java +++ b/guava-tests/test/com/google/common/math/BigIntegerMathTest.java @@ -37,6 +37,7 @@ import static java.math.RoundingMode.UP; import static java.math.RoundingMode.values; import static java.util.Arrays.asList; +import static org.junit.Assert.assertThrows; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -790,6 +791,33 @@ public void testNullPointers() { tester.testAllPublicStaticMethods(BigIntegerMath.class); } + public void testMultifactorialBasic() { + assertEquals(BigInteger.valueOf(105), BigIntegerMath.multiFactorial(7, 2)); // 7 * 5 * 3 * 1 + assertEquals(BigInteger.valueOf(28), BigIntegerMath.multiFactorial(7, 3)); // 7 * 4 * 1 + assertEquals(BigInteger.ONE, BigIntegerMath.multiFactorial(0, 1)); // Base case + assertEquals(BigInteger.ONE, BigIntegerMath.multiFactorial(1, 1)); // 1! + } + + public void testMultifactorialWithIncrementOne() { + assertEquals(BigInteger.valueOf(120), BigIntegerMath.multiFactorial(5, 1)); // 5 * 4 * 3 * 2 * 1 + } + + public void testMultifactorialNegativeIncrement() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + BigIntegerMath.multiFactorial(5, -1); + }); + assertEquals("Step value k must be a positive integer.", exception.getMessage()); + } + + public void testMultifactorialWithLargeNumber() { + assertEquals(new BigInteger("3628800"), BigIntegerMath.multiFactorial(10, 1)); + } + + public void testMultifactorialWithLargeInput() { + BigInteger result = BigIntegerMath.multiFactorial(100, 10); + assertTrue(result.compareTo(BigInteger.ZERO) > 0); // Result should be positive + } + @GwtIncompatible // String.format private static void failFormat(String template, Object... args) { fail(String.format(template, args)); diff --git a/guava-tests/test/com/google/common/math/IntMathTest.java b/guava-tests/test/com/google/common/math/IntMathTest.java index 73128e46803f..cb76f13e62fc 100644 --- a/guava-tests/test/com/google/common/math/IntMathTest.java +++ b/guava-tests/test/com/google/common/math/IntMathTest.java @@ -27,6 +27,7 @@ import static java.math.BigInteger.valueOf; import static java.math.RoundingMode.FLOOR; import static java.math.RoundingMode.UNNECESSARY; +import static org.junit.Assert.assertThrows; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -771,6 +772,33 @@ public void testIsPrime() { } } + public void testMultifactorialBasic() { + assertEquals(105, IntMath.multiFactorial(7, 2)); // 7 * 5 * 3 * 1 + assertEquals(28, IntMath.multiFactorial(7, 3)); // 7 * 4 * 1 + assertEquals(1, IntMath.multiFactorial(0, 1)); // Base case + assertEquals(1, IntMath.multiFactorial(1, 1)); // 1! + } + + public void testMultifactorialWithIncrementOne() { + assertEquals(120, IntMath.multiFactorial(5, 1)); // 5 * 4 * 3 * 2 * 1 + } + + public void testMultifactorialNegativeIncrement() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + IntMath.multiFactorial(5, -1); + }); + assertEquals("Step value k must be a positive integer.", exception.getMessage()); + } + + public void testMultifactorialWithLargeNumber() { + assertEquals(3628800, IntMath.multiFactorial(10, 1)); + } + + public void testMultifactorialWithLargeInput() { + int result = IntMath.multiFactorial(100, 10); + assertTrue(result > 0); // Result should be positive + } + private static int force32(int value) { // GWT doesn't consistently overflow values to make them 32-bit, so we need to force it. return value & 0xffffffff; diff --git a/guava-tests/test/com/google/common/math/LongMathTest.java b/guava-tests/test/com/google/common/math/LongMathTest.java index e5598c68792d..15ab005596a6 100644 --- a/guava-tests/test/com/google/common/math/LongMathTest.java +++ b/guava-tests/test/com/google/common/math/LongMathTest.java @@ -30,6 +30,7 @@ import static java.math.BigInteger.valueOf; import static java.math.RoundingMode.FLOOR; import static java.math.RoundingMode.UNNECESSARY; +import static org.junit.Assert.assertThrows; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; @@ -1025,6 +1026,33 @@ public void testRoundToDoubleAgainstBigIntegerUnnecessary() { } } + public void testMultifactorialBasic() { + assertEquals(105l, LongMath.multiFactorial(7, 2)); // 7 * 5 * 3 * 1 + assertEquals(28l, LongMath.multiFactorial(7, 3)); // 7 * 4 * 1 + assertEquals(1l, LongMath.multiFactorial(0, 1)); // Base case + assertEquals(1l, LongMath.multiFactorial(1, 1)); // 1! + } + + public void testMultifactorialWithIncrementOne() { + assertEquals(120l, LongMath.multiFactorial(5, 1)); // 5 * 4 * 3 * 2 * 1 + } + + public void testMultifactorialNegativeIncrement() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + LongMath.multiFactorial(5, -1); + }); + assertEquals("Step value k must be a positive integer.", exception.getMessage()); + } + + public void testMultifactorialWithLargeNumber() { + assertEquals(3628800l, LongMath.multiFactorial(10, 1)); + } + + public void testMultifactorialWithLargeInput() { + long result = LongMath.multiFactorial(100, 10); + assertTrue(result > 0l); // Result should be positive + } + private static void failFormat(String template, Object... args) { assertWithMessage(template, args).fail(); } diff --git a/guava/src/com/google/common/math/BigIntegerMath.java b/guava/src/com/google/common/math/BigIntegerMath.java index 5f7ce6b57577..1252139cdb2d 100644 --- a/guava/src/com/google/common/math/BigIntegerMath.java +++ b/guava/src/com/google/common/math/BigIntegerMath.java @@ -521,5 +521,29 @@ static boolean fitsInLong(BigInteger x) { return x.bitLength() <= Long.SIZE - 1; } + /** + * Computes the multifactorial of a given non-negative integer {@code n} + * with a specified step {@code k}. The multifactorial is defined as the + * product of all integers from {@code n} down to 1, decrementing by {@code k}. + * + * @param n the non-negative integer for which to compute the multifactorial + * @param k the step value (must be a positive integer) + * @return the computed multifactorial of {@code n} with step {@code k} + * @throws IllegalArgumentException if {@code k} is less than or equal to 0 + */ + public static BigInteger multiFactorial(int n, int k) { + if (k <= 0) { + throw new IllegalArgumentException("Step value k must be a positive integer."); + } + if (n <= 0) { + return BigInteger.ONE; // Base case for n <= 0 + } + BigInteger result = BigInteger.ONE; + for (int i = n; i > 0; i -= k) { + result = result.multiply(BigInteger.valueOf(i)); + } + return result; + } + private BigIntegerMath() {} } diff --git a/guava/src/com/google/common/math/IntMath.java b/guava/src/com/google/common/math/IntMath.java index 7ab7765cf840..aae41718a089 100644 --- a/guava/src/com/google/common/math/IntMath.java +++ b/guava/src/com/google/common/math/IntMath.java @@ -722,5 +722,29 @@ public static boolean isPrime(int n) { return LongMath.isPrime(n); } + /** + * Computes the multifactorial of a given non-negative integer {@code n} + * with a specified step {@code k}. The multifactorial is defined as the + * product of all integers from {@code n} down to 1, decrementing by {@code k}. + * + * @param n the non-negative integer for which to compute the multifactorial + * @param k the step value (must be a positive integer) + * @return the computed multifactorial of {@code n} with step {@code k} + * @throws IllegalArgumentException if {@code k} is less than or equal to 0 + */ + public static int multiFactorial(int n, int k) { + if (k <= 0) { + throw new IllegalArgumentException("Step value k must be a positive integer."); + } + if (n <= 0) { + return 1; // Base case for n <= 0 + } + int result = 1; + for (int i = n; i > 0; i -= k) { + result *= i; + } + return result; + } + private IntMath() {} } diff --git a/guava/src/com/google/common/math/LongMath.java b/guava/src/com/google/common/math/LongMath.java index 16e0248d99e4..1d24aaa5911a 100644 --- a/guava/src/com/google/common/math/LongMath.java +++ b/guava/src/com/google/common/math/LongMath.java @@ -1346,5 +1346,28 @@ public static double roundToDouble(long x, RoundingMode mode) { throw new AssertionError("impossible"); } - private LongMath() {} + /** + * Computes the multifactorial of a given non-negative integer {@code n} + * with a specified step {@code k}. The multifactorial is defined as the + * product of all integers from {@code n} down to 1, decrementing by {@code k}. + * + * @param n the non-negative integer for which to compute the multifactorial + * @param k the step value (must be a positive integer) + * @return the computed multifactorial of {@code n} with step {@code k} + * @throws IllegalArgumentException if {@code k} is less than or equal to 0 + */ + public static long multiFactorial(int n, int k) { + if (k <= 0) { + throw new IllegalArgumentException("Step value k must be a positive integer."); + } + if (n <= 0) { + return 1; // Base case for n <= 0 + } + long result = 1; + for (int i = n; i > 0; i -= k) { + result *= i; + } + return result; + } + }