diff --git a/Algorithms.Tests/Numeric/DoubleFactorialTests.cs b/Algorithms.Tests/Numeric/DoubleFactorialTests.cs new file mode 100644 index 00000000..7e08354f --- /dev/null +++ b/Algorithms.Tests/Numeric/DoubleFactorialTests.cs @@ -0,0 +1,54 @@ +using System.Numerics; +using Algorithms.Numeric; + +namespace Algorithms.Tests.Numeric; + +/// +/// Tests for the DoubleFactorial class methods. +/// +public static class DoubleFactorialTests +{ + /// + /// Tests the calculation of double factorial for non-negative integers. + /// Includes base cases (0, 1), odd numbers (5, 11), even numbers (6, 12), + /// and a large number (20) that benefits from BigInteger. + /// + /// The number N to calculate N!!. + /// The expected result as a string (for BigInteger parsing). + [TestCase(0, "1")] // Base Case: 0!! = 1 + [TestCase(1, "1")] // Base Case: 1!! = 1 + [TestCase(5, "15")] // Odd: 5 * 3 * 1 = 15 + [TestCase(6, "48")] // Even: 6 * 4 * 2 = 48 + [TestCase(11, "10395")]// Larger Odd: 11 * 9 * 7 * 5 * 3 * 1 = 10395 + [TestCase(12, "46080")] // Larger Even: 12 * 10 * 8 * 6 * 4 * 2 = 46080 + [TestCase(20, "3715891200")] // Large Even + public static void GetsDoubleFactorial(int input, string expected) + { + // Arrange + BigInteger expectedBigInt = BigInteger.Parse(expected); + + // Act + var result = DoubleFactorial.Calculate(input); + + // Assert + Assert.That(result, Is.EqualTo(expectedBigInt)); + } + + /// + /// Tests that calculating double factorial for negative numbers throws an ArgumentException. + /// + /// A negative integer input. + [TestCase(-1)] + [TestCase(-5)] + [TestCase(-10)] + public static void GetsDoubleFactorialExceptionForNegativeNumbers(int num) + { + // Arrange + + // Act + void Act() => DoubleFactorial.Calculate(num); + + // Assert + _ = Assert.Throws(Act); + } +} \ No newline at end of file diff --git a/Algorithms/Numeric/DoubleFactorial.cs b/Algorithms/Numeric/DoubleFactorial.cs new file mode 100644 index 00000000..65cb481b --- /dev/null +++ b/Algorithms/Numeric/DoubleFactorial.cs @@ -0,0 +1,48 @@ +using System.Numerics; + +namespace Algorithms.Numeric; + +/// +/// The double factorial of a positive integer n, denoted by n!!, +/// is the product of all integers from 1 up to n that have the same parity (odd or even) as n. +/// E.g., 5!! = 5 * 3 * 1 = 15, and 6!! = 6 * 4 * 2 = 48. +/// +public static class DoubleFactorial +{ + /// + /// Calculates the double factorial of a non-negative integer number. + /// + /// Non-negative integer input number. + /// Double factorial of the integer input number. + public static BigInteger Calculate(int inputNum) + { + // Don't calculate double factorial if input is a negative number. + if (inputNum < 0) + { + throw new ArgumentException("Double factorial is only defined for non-negative integers (num >= 0)."); + } + + // Base cases: 0!! = 1 and 1!! = 1 + if (inputNum <= 1) + { + return BigInteger.One; + } + + // Initialize result. + BigInteger result = BigInteger.One; + + // Start the iteration from the input number and step down by 2. + // This handles both odd (n, n-2, ..., 3, 1) and even (n, n-2, ..., 4, 2) cases naturally. + BigInteger current = inputNum; + + while (current > BigInteger.Zero) + { + result *= current; + + // Decrease the current number by 2 for the next factor. + current -= 2; + } + + return result; + } +}