diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa2480..175c5aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Added `All` and `Any` for `Span` and `ReadOnlySpan`, mimicking the corresponding methods in `System.Linq` - Added time-related extension methods (`Ticks`, `Milliseconds`, `Seconds`, `Minutes`, `Hours`, `Days`, and `Weeks`) to all built-in numeric types - Added `TimeSpan.Ago()` and `TimeSpan.FromNow()` +- Added `Factorial` extension method for built-in numeric types - Added `FileInfo.GetHash()` - Added `FileInfo.TryWriteHash(Span, out int)` - Added `IEnumerable.Product()` and `IEnumerable.Product(Func, TResult)` for all built-in numeric types, computing the product of all (transformed) elements diff --git a/X10D.Tests/src/Math/ByteTests.cs b/X10D.Tests/src/Math/ByteTests.cs new file mode 100644 index 0000000..41bf551 --- /dev/null +++ b/X10D.Tests/src/Math/ByteTests.cs @@ -0,0 +1,24 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +public class ByteTests +{ + [TestMethod] + public void FactorialShouldBeCorrect() + { + Assert.AreEqual(1L, ((byte)0).Factorial()); + Assert.AreEqual(1L, ((byte)1).Factorial()); + Assert.AreEqual(2L, ((byte)2).Factorial()); + Assert.AreEqual(6L, ((byte)3).Factorial()); + Assert.AreEqual(24L, ((byte)4).Factorial()); + Assert.AreEqual(120L, ((byte)5).Factorial()); + Assert.AreEqual(720L, ((byte)6).Factorial()); + Assert.AreEqual(5040L, ((byte)7).Factorial()); + Assert.AreEqual(40320L, ((byte)8).Factorial()); + Assert.AreEqual(362880L, ((byte)9).Factorial()); + Assert.AreEqual(3628800L, ((byte)10).Factorial()); + } +} diff --git a/X10D.Tests/src/Math/Int16Tests.cs b/X10D.Tests/src/Math/Int16Tests.cs new file mode 100644 index 0000000..6a31d3b --- /dev/null +++ b/X10D.Tests/src/Math/Int16Tests.cs @@ -0,0 +1,30 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +public class Int16Tests +{ + [TestMethod] + public void FactorialShouldBeCorrect() + { + Assert.AreEqual(1L, ((short)0).Factorial()); + Assert.AreEqual(1L, ((short)1).Factorial()); + Assert.AreEqual(2L, ((short)2).Factorial()); + Assert.AreEqual(6L, ((short)3).Factorial()); + Assert.AreEqual(24L, ((short)4).Factorial()); + Assert.AreEqual(120L, ((short)5).Factorial()); + Assert.AreEqual(720L, ((short)6).Factorial()); + Assert.AreEqual(5040L, ((short)7).Factorial()); + Assert.AreEqual(40320L, ((short)8).Factorial()); + Assert.AreEqual(362880L, ((short)9).Factorial()); + Assert.AreEqual(3628800L, ((short)10).Factorial()); + } + + [TestMethod] + public void NegativeFactorialShouldThrow() + { + Assert.ThrowsException(() => ((short)-1).Factorial()); + } +} diff --git a/X10D.Tests/src/Math/Int32Tests.cs b/X10D.Tests/src/Math/Int32Tests.cs new file mode 100644 index 0000000..c358d7a --- /dev/null +++ b/X10D.Tests/src/Math/Int32Tests.cs @@ -0,0 +1,30 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +public class Int32Tests +{ + [TestMethod] + public void FactorialShouldBeCorrect() + { + Assert.AreEqual(1L, 0.Factorial()); + Assert.AreEqual(1L, 1.Factorial()); + Assert.AreEqual(2L, 2.Factorial()); + Assert.AreEqual(6L, 3.Factorial()); + Assert.AreEqual(24L, 4.Factorial()); + Assert.AreEqual(120L, 5.Factorial()); + Assert.AreEqual(720L, 6.Factorial()); + Assert.AreEqual(5040L, 7.Factorial()); + Assert.AreEqual(40320L, 8.Factorial()); + Assert.AreEqual(362880L, 9.Factorial()); + Assert.AreEqual(3628800L, 10.Factorial()); + } + + [TestMethod] + public void NegativeFactorialShouldThrow() + { + Assert.ThrowsException(() => (-1).Factorial()); + } +} diff --git a/X10D.Tests/src/Math/Int64Tests.cs b/X10D.Tests/src/Math/Int64Tests.cs new file mode 100644 index 0000000..a1b21af --- /dev/null +++ b/X10D.Tests/src/Math/Int64Tests.cs @@ -0,0 +1,30 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +public class Int64Tests +{ + [TestMethod] + public void FactorialShouldBeCorrect() + { + Assert.AreEqual(1L, 0L.Factorial()); + Assert.AreEqual(1L, 1L.Factorial()); + Assert.AreEqual(2L, 2L.Factorial()); + Assert.AreEqual(6L, 3L.Factorial()); + Assert.AreEqual(24L, 4L.Factorial()); + Assert.AreEqual(120L, 5L.Factorial()); + Assert.AreEqual(720L, 6L.Factorial()); + Assert.AreEqual(5040L, 7L.Factorial()); + Assert.AreEqual(40320L, 8L.Factorial()); + Assert.AreEqual(362880L, 9L.Factorial()); + Assert.AreEqual(3628800L, 10L.Factorial()); + } + + [TestMethod] + public void NegativeFactorialShouldThrow() + { + Assert.ThrowsException(() => (-1L).Factorial()); + } +} diff --git a/X10D.Tests/src/Math/SByteTests.cs b/X10D.Tests/src/Math/SByteTests.cs new file mode 100644 index 0000000..c5279bb --- /dev/null +++ b/X10D.Tests/src/Math/SByteTests.cs @@ -0,0 +1,31 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +[CLSCompliant(false)] +public class SByteTests +{ + [TestMethod] + public void FactorialShouldBeCorrect() + { + Assert.AreEqual(1L, ((sbyte)0).Factorial()); + Assert.AreEqual(1L, ((sbyte)1).Factorial()); + Assert.AreEqual(2L, ((sbyte)2).Factorial()); + Assert.AreEqual(6L, ((sbyte)3).Factorial()); + Assert.AreEqual(24L, ((sbyte)4).Factorial()); + Assert.AreEqual(120L, ((sbyte)5).Factorial()); + Assert.AreEqual(720L, ((sbyte)6).Factorial()); + Assert.AreEqual(5040L, ((sbyte)7).Factorial()); + Assert.AreEqual(40320L, ((sbyte)8).Factorial()); + Assert.AreEqual(362880L, ((sbyte)9).Factorial()); + Assert.AreEqual(3628800L, ((sbyte)10).Factorial()); + } + + [TestMethod] + public void NegativeFactorialShouldThrow() + { + Assert.ThrowsException(() => ((sbyte)-1).Factorial()); + } +} diff --git a/X10D.Tests/src/Math/UInt16Tests.cs b/X10D.Tests/src/Math/UInt16Tests.cs new file mode 100644 index 0000000..27619e9 --- /dev/null +++ b/X10D.Tests/src/Math/UInt16Tests.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +[CLSCompliant(false)] +public class UInt16Tests +{ + [TestMethod] + public void FactorialShouldBeCorrect() + { + Assert.AreEqual(1UL, ((ushort)0).Factorial()); + Assert.AreEqual(1UL, ((ushort)1).Factorial()); + Assert.AreEqual(2UL, ((ushort)2).Factorial()); + Assert.AreEqual(6UL, ((ushort)3).Factorial()); + Assert.AreEqual(24UL, ((ushort)4).Factorial()); + Assert.AreEqual(120UL, ((ushort)5).Factorial()); + Assert.AreEqual(720UL, ((ushort)6).Factorial()); + Assert.AreEqual(5040UL, ((ushort)7).Factorial()); + Assert.AreEqual(40320UL, ((ushort)8).Factorial()); + Assert.AreEqual(362880UL, ((ushort)9).Factorial()); + Assert.AreEqual(3628800UL, ((ushort)10).Factorial()); + } +} diff --git a/X10D.Tests/src/Math/UInt32Tests.cs b/X10D.Tests/src/Math/UInt32Tests.cs new file mode 100644 index 0000000..dc0fbf0 --- /dev/null +++ b/X10D.Tests/src/Math/UInt32Tests.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +[CLSCompliant(false)] +public class UInt32Tests +{ + [TestMethod] + public void FactorialShouldBeCorrect() + { + Assert.AreEqual(1UL, 0U.Factorial()); + Assert.AreEqual(1UL, 1U.Factorial()); + Assert.AreEqual(2UL, 2U.Factorial()); + Assert.AreEqual(6UL, 3U.Factorial()); + Assert.AreEqual(24UL, 4U.Factorial()); + Assert.AreEqual(120UL, 5U.Factorial()); + Assert.AreEqual(720UL, 6U.Factorial()); + Assert.AreEqual(5040UL, 7U.Factorial()); + Assert.AreEqual(40320UL, 8U.Factorial()); + Assert.AreEqual(362880UL, 9U.Factorial()); + Assert.AreEqual(3628800UL, 10U.Factorial()); + } +} diff --git a/X10D.Tests/src/Math/UInt64Tests.cs b/X10D.Tests/src/Math/UInt64Tests.cs new file mode 100644 index 0000000..0e02a77 --- /dev/null +++ b/X10D.Tests/src/Math/UInt64Tests.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +[CLSCompliant(false)] +public class UInt64Tests +{ + [TestMethod] + public void FactorialShouldBeCorrect() + { + Assert.AreEqual(1UL, 0UL.Factorial()); + Assert.AreEqual(1UL, 1UL.Factorial()); + Assert.AreEqual(2UL, 2UL.Factorial()); + Assert.AreEqual(6UL, 3UL.Factorial()); + Assert.AreEqual(24UL, 4UL.Factorial()); + Assert.AreEqual(120UL, 5UL.Factorial()); + Assert.AreEqual(720UL, 6UL.Factorial()); + Assert.AreEqual(5040UL, 7UL.Factorial()); + Assert.AreEqual(40320UL, 8UL.Factorial()); + Assert.AreEqual(362880UL, 9UL.Factorial()); + Assert.AreEqual(3628800UL, 10UL.Factorial()); + } +} diff --git a/X10D/src/Math/ByteExtensions.cs b/X10D/src/Math/ByteExtensions.cs new file mode 100644 index 0000000..fdbd177 --- /dev/null +++ b/X10D/src/Math/ByteExtensions.cs @@ -0,0 +1,28 @@ +namespace X10D.Math; + +/// +/// Extension methods for . +/// +public static class ByteExtensions +{ + /// + /// Returns the factorial of the current 8-bit unsigned integer. + /// + /// The value whose factorial to compute. + /// The factorial of . + public static long Factorial(this byte value) + { + if (value == 0) + { + return 1; + } + + var result = 1L; + for (byte i = 1; i <= value; i++) + { + result *= i; + } + + return result; + } +} diff --git a/X10D/src/Math/Int16Extensions.cs b/X10D/src/Math/Int16Extensions.cs new file mode 100644 index 0000000..620ce0f --- /dev/null +++ b/X10D/src/Math/Int16Extensions.cs @@ -0,0 +1,34 @@ +namespace X10D.Math; + +/// +/// Extension methods for . +/// +public static class Int16Extensions +{ + /// + /// Returns the factorial of the current 16-bit signed integer. + /// + /// The value whose factorial to compute. + /// The factorial of . + /// is less than 0. + public static long Factorial(this short value) + { + if (value < 0) + { + throw new ArithmeticException(nameof(value)); + } + + if (value == 0) + { + return 1; + } + + var result = 1L; + for (short i = 1; i <= value; i++) + { + result *= i; + } + + return result; + } +} diff --git a/X10D/src/Math/Int32Extensions.cs b/X10D/src/Math/Int32Extensions.cs new file mode 100644 index 0000000..bc73e36 --- /dev/null +++ b/X10D/src/Math/Int32Extensions.cs @@ -0,0 +1,34 @@ +namespace X10D.Math; + +/// +/// Extension methods for . +/// +public static class Int32Extensions +{ + /// + /// Returns the factorial of the current 32-bit signed integer. + /// + /// The value whose factorial to compute. + /// The factorial of . + /// is less than 0. + public static long Factorial(this int value) + { + if (value < 0) + { + throw new ArithmeticException(nameof(value)); + } + + if (value == 0) + { + return 1; + } + + var result = 1L; + for (var i = 1; i <= value; i++) + { + result *= i; + } + + return result; + } +} diff --git a/X10D/src/Math/Int64Extensions.cs b/X10D/src/Math/Int64Extensions.cs new file mode 100644 index 0000000..696e037 --- /dev/null +++ b/X10D/src/Math/Int64Extensions.cs @@ -0,0 +1,34 @@ +namespace X10D.Math; + +/// +/// Extension methods for . +/// +public static class Int64Extensions +{ + /// + /// Returns the factorial of the current 64-bit signed integer. + /// + /// The value whose factorial to compute. + /// The factorial of . + /// is less than 0. + public static long Factorial(this long value) + { + if (value < 0) + { + throw new ArithmeticException(nameof(value)); + } + + if (value == 0) + { + return 1; + } + + var result = 1L; + for (var i = 1L; i <= value; i++) + { + result *= i; + } + + return result; + } +} diff --git a/X10D/src/Math/SByteExtensions.cs b/X10D/src/Math/SByteExtensions.cs new file mode 100644 index 0000000..d9bc296 --- /dev/null +++ b/X10D/src/Math/SByteExtensions.cs @@ -0,0 +1,35 @@ +namespace X10D.Math; + +/// +/// Extension methods for . +/// +[CLSCompliant(false)] +public static class SByteExtensions +{ + /// + /// Returns the factorial of the current 8-bit signed integer. + /// + /// The value whose factorial to compute. + /// The factorial of . + /// is less than 0. + public static long Factorial(this sbyte value) + { + if (value < 0) + { + throw new ArithmeticException(nameof(value)); + } + + if (value == 0) + { + return 1; + } + + var result = 1L; + for (ushort i = 1; i <= value; i++) + { + result *= i; + } + + return result; + } +} diff --git a/X10D/src/Math/UInt16Extensions.cs b/X10D/src/Math/UInt16Extensions.cs new file mode 100644 index 0000000..bdbe702 --- /dev/null +++ b/X10D/src/Math/UInt16Extensions.cs @@ -0,0 +1,29 @@ +namespace X10D.Math; + +/// +/// Extension methods for . +/// +[CLSCompliant(false)] +public static class UInt16Extensions +{ + /// + /// Returns the factorial of the current 16-bit unsigned integer. + /// + /// The value whose factorial to compute. + /// The factorial of . + public static ulong Factorial(this ushort value) + { + if (value == 0) + { + return 1; + } + + var result = 1UL; + for (ushort i = 1; i <= value; i++) + { + result *= i; + } + + return result; + } +} diff --git a/X10D/src/Math/UInt32Extensions.cs b/X10D/src/Math/UInt32Extensions.cs new file mode 100644 index 0000000..5f1aec0 --- /dev/null +++ b/X10D/src/Math/UInt32Extensions.cs @@ -0,0 +1,29 @@ +namespace X10D.Math; + +/// +/// Extension methods for . +/// +[CLSCompliant(false)] +public static class UInt32Extensions +{ + /// + /// Returns the factorial of the current 32-bit unsigned integer. + /// + /// The value whose factorial to compute. + /// The factorial of . + public static ulong Factorial(this uint value) + { + if (value == 0) + { + return 1; + } + + var result = 1UL; + for (var i = 1U; i <= value; i++) + { + result *= i; + } + + return result; + } +} diff --git a/X10D/src/Math/UInt64Extensions.cs b/X10D/src/Math/UInt64Extensions.cs new file mode 100644 index 0000000..3be7e06 --- /dev/null +++ b/X10D/src/Math/UInt64Extensions.cs @@ -0,0 +1,29 @@ +namespace X10D.Math; + +/// +/// Extension methods for . +/// +[CLSCompliant(false)] +public static class UInt64Extensions +{ + /// + /// Returns the factorial of the current 64-bit unsigned integer. + /// + /// The value whose factorial to compute. + /// The factorial of . + public static ulong Factorial(this ulong value) + { + if (value == 0) + { + return 1; + } + + var result = 1UL; + for (var i = 1UL; i <= value; i++) + { + result *= i; + } + + return result; + } +}