Skip to content

Commit 86374cd

Browse files
author
Lê Nam Khánh
authored
feat: add method DoubleFactorial (#567)
1 parent 6c3203b commit 86374cd

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Numerics;
2+
using Algorithms.Numeric;
3+
4+
namespace Algorithms.Tests.Numeric;
5+
6+
/// <summary>
7+
/// Tests for the DoubleFactorial class methods.
8+
/// </summary>
9+
public static class DoubleFactorialTests
10+
{
11+
/// <summary>
12+
/// Tests the calculation of double factorial for non-negative integers.
13+
/// Includes base cases (0, 1), odd numbers (5, 11), even numbers (6, 12),
14+
/// and a large number (20) that benefits from BigInteger.
15+
/// </summary>
16+
/// <param name="input">The number N to calculate N!!.</param>
17+
/// <param name="expected">The expected result as a string (for BigInteger parsing).</param>
18+
[TestCase(0, "1")] // Base Case: 0!! = 1
19+
[TestCase(1, "1")] // Base Case: 1!! = 1
20+
[TestCase(5, "15")] // Odd: 5 * 3 * 1 = 15
21+
[TestCase(6, "48")] // Even: 6 * 4 * 2 = 48
22+
[TestCase(11, "10395")]// Larger Odd: 11 * 9 * 7 * 5 * 3 * 1 = 10395
23+
[TestCase(12, "46080")] // Larger Even: 12 * 10 * 8 * 6 * 4 * 2 = 46080
24+
[TestCase(20, "3715891200")] // Large Even
25+
public static void GetsDoubleFactorial(int input, string expected)
26+
{
27+
// Arrange
28+
BigInteger expectedBigInt = BigInteger.Parse(expected);
29+
30+
// Act
31+
var result = DoubleFactorial.Calculate(input);
32+
33+
// Assert
34+
Assert.That(result, Is.EqualTo(expectedBigInt));
35+
}
36+
37+
/// <summary>
38+
/// Tests that calculating double factorial for negative numbers throws an ArgumentException.
39+
/// </summary>
40+
/// <param name="num">A negative integer input.</param>
41+
[TestCase(-1)]
42+
[TestCase(-5)]
43+
[TestCase(-10)]
44+
public static void GetsDoubleFactorialExceptionForNegativeNumbers(int num)
45+
{
46+
// Arrange
47+
48+
// Act
49+
void Act() => DoubleFactorial.Calculate(num);
50+
51+
// Assert
52+
_ = Assert.Throws<ArgumentException>(Act);
53+
}
54+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System.Numerics;
2+
3+
namespace Algorithms.Numeric;
4+
5+
/// <summary>
6+
/// The double factorial of a positive integer n, denoted by n!!,
7+
/// is the product of all integers from 1 up to n that have the same parity (odd or even) as n.
8+
/// E.g., 5!! = 5 * 3 * 1 = 15, and 6!! = 6 * 4 * 2 = 48.
9+
/// </summary>
10+
public static class DoubleFactorial
11+
{
12+
/// <summary>
13+
/// Calculates the double factorial of a non-negative integer number.
14+
/// </summary>
15+
/// <param name="inputNum">Non-negative integer input number.</param>
16+
/// <returns>Double factorial of the integer input number.</returns>
17+
public static BigInteger Calculate(int inputNum)
18+
{
19+
// Don't calculate double factorial if input is a negative number.
20+
if (inputNum < 0)
21+
{
22+
throw new ArgumentException("Double factorial is only defined for non-negative integers (num >= 0).");
23+
}
24+
25+
// Base cases: 0!! = 1 and 1!! = 1
26+
if (inputNum <= 1)
27+
{
28+
return BigInteger.One;
29+
}
30+
31+
// Initialize result.
32+
BigInteger result = BigInteger.One;
33+
34+
// Start the iteration from the input number and step down by 2.
35+
// This handles both odd (n, n-2, ..., 3, 1) and even (n, n-2, ..., 4, 2) cases naturally.
36+
BigInteger current = inputNum;
37+
38+
while (current > BigInteger.Zero)
39+
{
40+
result *= current;
41+
42+
// Decrease the current number by 2 for the next factor.
43+
current -= 2;
44+
}
45+
46+
return result;
47+
}
48+
}

0 commit comments

Comments
 (0)