Skip to content

Commit 9104ebc

Browse files
Switch factorial calculation to big integer (TheAlgorithms#393)
1 parent 97bdcbd commit 9104ebc

File tree

4 files changed

+37
-26
lines changed

4 files changed

+37
-26
lines changed

Algorithms.Tests/Numeric/FactorialTests.cs

+13-15
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,39 @@
11
using System;
2+
using System.Numerics;
23
using Algorithms.Numeric;
34
using NUnit.Framework;
45

56
namespace Algorithms.Tests.Numeric
67
{
78
public static class FactorialTests
89
{
9-
[Test]
10-
[TestCase(5, 120)]
11-
[TestCase(1, 1)]
12-
[TestCase(0, 1)]
13-
[TestCase(4, 24)]
14-
[TestCase(18, 6402373705728000)]
15-
[TestCase(10, 3628800)]
16-
public static void GetsFactorial(int input, long expected)
10+
[TestCase(0, "1")]
11+
[TestCase(1, "1")]
12+
[TestCase(4, "24")]
13+
[TestCase(10, "3628800")]
14+
[TestCase(18, "6402373705728000")]
15+
public static void GetsFactorial(int input, string expected)
1716
{
1817
// Arrange
18+
BigInteger expectedBigInt = BigInteger.Parse(expected);
1919

2020
// Act
2121
var result = Factorial.Calculate(input);
2222

2323
// Assert
24-
Assert.AreEqual(expected, result);
24+
Assert.AreEqual(expectedBigInt, result);
2525
}
2626

27-
[Test]
28-
public static void GetsFactorialExceptionForNonPositiveNumbers(
29-
[Random(-1000, -1, 10, Distinct = true)]
30-
int input)
27+
[TestCase(-5)]
28+
[TestCase(-10)]
29+
public static void GetsFactorialExceptionForNegativeNumbers(int num)
3130
{
3231
// Arrange
3332

3433
// Act
35-
void Act() => Factorial.Calculate(input);
34+
void Act() => Factorial.Calculate(num);
3635

3736
// Assert
38-
3937
_ = Assert.Throws<ArgumentException>(Act);
4038
}
4139
}

Algorithms.Tests/Strings/PermutationTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Numerics;
45
using Algorithms.Numeric;
56
using Algorithms.Strings;
6-
using FluentAssertions;
77
using NUnit.Framework;
88

99
namespace Algorithms.Tests.Strings
@@ -48,7 +48,7 @@ public void Test_GetEveryUniquePermutation(string word)
4848
{
4949
return current / Factorial.Calculate(keyValuePair.Value);
5050
});
51-
Assert.AreEqual(expectedNumberOfAnagrams, permutations.Count);
51+
Assert.AreEqual(expectedNumberOfAnagrams, new BigInteger(permutations.Count));
5252
// End 1.
5353

5454
// Start 2

Algorithms/Numeric/Factorial.cs

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Numerics;
23

34
namespace Algorithms.Numeric
45
{
@@ -9,18 +10,30 @@ namespace Algorithms.Numeric
910
public static class Factorial
1011
{
1112
/// <summary>
12-
/// Calculates factorial of a number.
13+
/// Calculates factorial of a integer number.
1314
/// </summary>
14-
/// <param name="num">Input number.</param>
15-
/// <returns>Factorial of input number.</returns>
16-
public static long Calculate(int num)
15+
/// <param name="inputNum">Integer Input number.</param>
16+
/// <returns>Factorial of integer input number.</returns>
17+
public static BigInteger Calculate(int inputNum)
1718
{
18-
if (num < 0)
19+
// Convert integer input to BigInteger
20+
BigInteger num = new BigInteger(inputNum);
21+
22+
// Don't calculate factorial if input is a negative number.
23+
if (BigInteger.Compare(num, BigInteger.Zero) < 0)
1924
{
2025
throw new ArgumentException("Only for num >= 0");
2126
}
2227

23-
return num == 0 ? 1 : num * Calculate(num - 1);
28+
// Factorial of numbers greater than 0.
29+
BigInteger result = BigInteger.One;
30+
31+
for (BigInteger i = BigInteger.One; BigInteger.Compare(i, num) <= 0; i = BigInteger.Add(i, BigInteger.One))
32+
{
33+
result = BigInteger.Multiply(result, i);
34+
}
35+
36+
return result;
2437
}
2538
}
2639
}

Algorithms/Numeric/Series/Maclaurin.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ private static double ErrorTermWrapper(double x, double error, Func<double, int,
117117
/// <param name="x">Given point.</param>
118118
/// <param name="i">Term index from 0 to n.</param>
119119
/// <returns>Single term value.</returns>
120-
private static double ExpTerm(double x, int i) => Math.Pow(x, i) / Factorial.Calculate(i);
120+
private static double ExpTerm(double x, int i) => Math.Pow(x, i) / (long)Factorial.Calculate(i);
121121

122122
/// <summary>
123123
/// Single term for sin(x) function approximation: (-1)^i * x^(2*i + 1) / (2*i + 1)!.
@@ -126,7 +126,7 @@ private static double ErrorTermWrapper(double x, double error, Func<double, int,
126126
/// <param name="i">Term index from 0 to n.</param>
127127
/// <returns>Single term value.</returns>
128128
private static double SinTerm(double x, int i) =>
129-
Math.Pow(-1, i) / Factorial.Calculate(2 * i + 1) * Math.Pow(x, 2 * i + 1);
129+
Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i + 1)) * Math.Pow(x, 2 * i + 1);
130130

131131
/// <summary>
132132
/// Single term for cos(x) function approximation: (-1)^i * x^(2*i) / (2*i)!.
@@ -135,6 +135,6 @@ private static double SinTerm(double x, int i) =>
135135
/// <param name="i">Term index from 0 to n.</param>
136136
/// <returns>Single term value.</returns>
137137
private static double CosTerm(double x, int i) =>
138-
Math.Pow(-1, i) / Factorial.Calculate(2 * i) * Math.Pow(x, 2 * i);
138+
Math.Pow(-1, i) / ((long)Factorial.Calculate(2 * i)) * Math.Pow(x, 2 * i);
139139
}
140140
}

0 commit comments

Comments
 (0)