Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions Algorithms.Tests/Numeric/DoubleFactorialTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Numerics;
using Algorithms.Numeric;

namespace Algorithms.Tests.Numeric;

/// <summary>
/// Tests for the DoubleFactorial class methods.
/// </summary>
public static class DoubleFactorialTests
{
/// <summary>
/// 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.
/// </summary>
/// <param name="input">The number N to calculate N!!.</param>
/// <param name="expected">The expected result as a string (for BigInteger parsing).</param>
[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));
}

/// <summary>
/// Tests that calculating double factorial for negative numbers throws an ArgumentException.
/// </summary>
/// <param name="num">A negative integer input.</param>
[TestCase(-1)]
[TestCase(-5)]
[TestCase(-10)]
public static void GetsDoubleFactorialExceptionForNegativeNumbers(int num)
{
// Arrange

// Act
void Act() => DoubleFactorial.Calculate(num);

// Assert
_ = Assert.Throws<ArgumentException>(Act);
}
}
48 changes: 48 additions & 0 deletions Algorithms/Numeric/DoubleFactorial.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Numerics;

namespace Algorithms.Numeric;

/// <summary>
/// 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.
/// </summary>
public static class DoubleFactorial
{
/// <summary>
/// Calculates the double factorial of a non-negative integer number.
/// </summary>
/// <param name="inputNum">Non-negative integer input number.</param>
/// <returns>Double factorial of the integer input number.</returns>
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;
}
}