diff --git a/README.rst b/README.rst index 356b3245..9522852c 100644 --- a/README.rst +++ b/README.rst @@ -68,7 +68,7 @@ Olivia's Project Euler Solutions | | C++14+ in: |msvc| [1]_ | | |CodeQL| |br| | | | |br| Browser [3]_ | | |Cp-lint| | +------------+----------------------------+--------+-------------------+ -| C# | .NET 2+ | 19 | |C#i| |br| | +| C# | .NET 2+ | 21 | |C#i| |br| | | | | | |Cs-Cov| |br| | | | | | |CodeQL| |br| | | | | | |C#-lint| | diff --git a/csharp/Euler.Test/test.cs b/csharp/Euler.Test/test.cs index 9e584414..0e8e803b 100644 --- a/csharp/Euler.Test/test.cs +++ b/csharp/Euler.Test/test.cs @@ -13,8 +13,10 @@ public static IEnumerable Data() yield return new object[] { typeof(p0003), false, Utilities.GetAnswer(3) }; yield return new object[] { typeof(p0004), false, Utilities.GetAnswer(4) }; yield return new object[] { typeof(p0006), false, Utilities.GetAnswer(6) }; + yield return new object[] { typeof(p0007), false, Utilities.GetAnswer(7) }; yield return new object[] { typeof(p0008), false, Utilities.GetAnswer(8) }; yield return new object[] { typeof(p0009), false, Utilities.GetAnswer(9) }; + yield return new object[] { typeof(p0010), false, Utilities.GetAnswer(10) }; yield return new object[] { typeof(p0011), false, Utilities.GetAnswer(11) }; yield return new object[] { typeof(p0013), false, Utilities.GetAnswer(13) }; yield return new object[] { typeof(p0014), false, Utilities.GetAnswer(14) }; @@ -65,7 +67,7 @@ public void EulerTest_Prime_Primes() List results = new() { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }; - var comparison = Prime.Primes().GetEnumerator(); + var comparison = Prime.Primes().GetEnumerator(); for (byte i = 0; i < results.Count; i += 1) { long expected = results[i]; @@ -80,11 +82,11 @@ public void EulerTest_Prime_PrimeFactors() List candidates = new() { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }; - foreach (long x in candidates) + foreach (long x in candidates) { - foreach (long y in candidates) + foreach (long y in candidates) { - List result = new(Prime.PrimeFactors(x * y)); + List result = new(Prime.PrimeFactors(x * y)); Assert.Contains(x, result); Assert.Contains(y, result); } diff --git a/csharp/Euler/include/prime.cs b/csharp/Euler/include/prime.cs index 1859bbcb..fc9d7e9c 100644 --- a/csharp/Euler/include/prime.cs +++ b/csharp/Euler/include/prime.cs @@ -1,24 +1,41 @@ using System; +using System.Collections.Generic; namespace Euler { public static class Prime { - private static long lastCached = 0; - private static List cache = new(); + private static readonly Dictionary Cache)> Caches = new(); - public static IEnumerable Primes(long? stop = null) + public static IEnumerable Primes(T? stop = null) where T : struct { - if (stop is null) + foreach (dynamic p in _Primes(stop)) { - foreach (var p in cache) + yield return (T) p; + } + } + + private static IEnumerable _Primes(dynamic? stop = null) + { + Type type = stop != null ? stop.GetType() : typeof(long); + if (!Caches.TryGetValue(type, out var cacheData)) + { + cacheData = (LastCached: (dynamic)0, Cache: new List()); + Caches[type] = cacheData; + } + (dynamic lastCached, List cache) = cacheData; + + // Yield cached values + if (stop == null) + { + foreach (dynamic p in cache) { yield return p; } } else { - foreach (var p in cache) + foreach (dynamic p in cache) { if (p < stop) yield return p; @@ -26,36 +43,41 @@ public static IEnumerable Primes(long? stop = null) break; } } - if (stop is not null && lastCached > stop) + + // Generate new primes + if (stop != null && lastCached > stop) yield break; - foreach (var p in ModifiedEratosthenes()) + + foreach (dynamic p in ModifiedEratosthenes()) { if (p <= lastCached) continue; - if (stop is not null && p > stop) + if (stop != null && p > stop) break; + cache.Add(p); lastCached = p; + Caches[type] = (lastCached, cache); yield return p; } } - private static IEnumerable ModifiedEratosthenes() + private static IEnumerable ModifiedEratosthenes() { yield return 2; yield return 3; yield return 5; yield return 7; - Dictionary sieve = new(); + var sieve = new Dictionary(); var recurse = ModifiedEratosthenes().GetEnumerator(); recurse.MoveNext(); recurse.MoveNext(); - long prime = recurse.Current; + dynamic prime = recurse.Current; if (prime != 3) throw new Exception(); - long primeSquared = prime * prime; - long step = 2; - for (long candidate = 9; ; candidate += 2) + dynamic primeSquared = prime * prime; + dynamic step = 2; + for (dynamic candidate = 9; ; candidate += 2) { if (sieve.ContainsKey(candidate)) { @@ -74,7 +96,7 @@ private static IEnumerable ModifiedEratosthenes() prime = recurse.Current; primeSquared = prime * prime; } - long tc = candidate; + dynamic tc = candidate; do { tc += step; @@ -83,7 +105,15 @@ private static IEnumerable ModifiedEratosthenes() } } - public static IEnumerable PrimeFactors(long n) + public static IEnumerable PrimeFactors(T n) where T : struct + { + foreach (dynamic f in _PrimeFactors(n)) + { + yield return (T) f; + } + } + + private static IEnumerable _PrimeFactors(dynamic n) { if (n < 0) { @@ -96,10 +126,10 @@ public static IEnumerable PrimeFactors(long n) } else { - long root = (long)Math.Ceiling(Math.Sqrt(n)); - foreach (long factor in Primes()) + dynamic root = (dynamic)Math.Ceiling(Math.Sqrt((double)n)); + foreach (dynamic factor in _Primes()) { - long modulo = n % factor; + dynamic modulo = n % factor; if (modulo == 0) { do @@ -108,7 +138,7 @@ public static IEnumerable PrimeFactors(long n) n /= factor; modulo = n % factor; } while (modulo == 0); - root = (long)Math.Ceiling(Math.Sqrt(n)); + root = (dynamic)Math.Ceiling(Math.Sqrt((double)n)); } if (n <= 1) break; @@ -121,21 +151,21 @@ public static IEnumerable PrimeFactors(long n) } } - public static long isComposite(long n) + public static dynamic IsComposite(dynamic n) { var factors = PrimeFactors(n).GetEnumerator(); factors.MoveNext(); - long first = factors.Current; + dynamic first = factors.Current; if (first == n) return 0; return first; } - public static bool isPrime(long n) + public static bool IsPrime(dynamic n) { if (n < 2) return false; - return isComposite(n) == 0; + return IsComposite(n) == 0; } } } diff --git a/csharp/Euler/p0007.cs b/csharp/Euler/p0007.cs new file mode 100644 index 00000000..c3d35d74 --- /dev/null +++ b/csharp/Euler/p0007.cs @@ -0,0 +1,29 @@ +/* +Project Euler Problem 7 + +Problem: + +By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that +the 6th prime is 13. + +What is the 10 001st prime number? +*/ +using System; + +namespace Euler +{ + public class p0007 : IEuler + { + public object Answer() + { + int i = 0; + foreach (long p in Prime.Primes()) + { + if (i == 10000) + return (int)p; + i++; + } + return -1; + } + } +} diff --git a/csharp/Euler/p0010.cs b/csharp/Euler/p0010.cs new file mode 100644 index 00000000..fcf4dcd8 --- /dev/null +++ b/csharp/Euler/p0010.cs @@ -0,0 +1,21 @@ +/* +Project Euler Problem 10 + +Problem: + +The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17. + +Find the sum of all the primes below two million. +*/ +using System; + +namespace Euler +{ + public class p0010 : IEuler + { + public object Answer() + { + return Enumerable.Sum(Prime.Primes(2000000)); + } + } +} diff --git a/csharp/Makefile b/csharp/Makefile index cdfbb696..b3f7dd49 100644 --- a/csharp/Makefile +++ b/csharp/Makefile @@ -23,7 +23,7 @@ clean: .PHONY: test test: ../LICENSE ifneq ($(NOT_TERMUX),0) - @dotnet test --nologo $(cov_args) + @dotnet test --nologo -l "console;verbosity=normal" $(cov_args) endif .PHONY: test_% diff --git a/csharp/README.rst b/csharp/README.rst index 7805e24a..fd74c365 100644 --- a/csharp/README.rst +++ b/csharp/README.rst @@ -81,8 +81,10 @@ Problems Solved - ☒ `3 <./Euler/p0003.cs>`__ - ☒ `4 <./Euler/p0004.cs>`__ - ☒ `6 <./Euler/p0006.cs>`__ +- ☒ `7 <./Euler/p0007.cs>`__ - ☒ `8 <./Euler/p0008.cs>`__ - ☒ `9 <./Euler/p0009.cs>`__ +- ☒ `10 <./Euler/p0010.cs>`__ - ☒ `11 <./Euler/p0011.cs>`__ - ☒ `13 <./Euler/p0013.cs>`__ - ☒ `14 <./Euler/p0014.cs>`__ diff --git a/docs/index.rst b/docs/index.rst index 62c48580..e61318ee 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -88,13 +88,13 @@ Problems Solved +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`6` |:c-d:`0006` |:cp-d:`0006`|:cs-d:`0006`|:ja-d:`0006`|:js-d:`0006`|:py-d:`0006`|:rs-d:`0006`| +-----------+------------+------------+------------+------------+------------+------------+------------+ -|:prob:`7` |:c-d:`0007` | | | |:js-d:`0007`|:py-d:`0007`|:rs-d:`0007`| +|:prob:`7` |:c-d:`0007` | |:cs-d:`0007`| |:js-d:`0007`|:py-d:`0007`|:rs-d:`0007`| +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`8` |:c-d:`0008` |:cp-d:`0008`|:cs-d:`0008`|:ja-d:`0008`|:js-d:`0008`|:py-d:`0008`|:rs-d:`0008`| +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`9` |:c-d:`0009` |:cp-d:`0009`|:cs-d:`0009`|:ja-d:`0009`|:js-d:`0009`|:py-d:`0009`|:rs-d:`0009`| +-----------+------------+------------+------------+------------+------------+------------+------------+ -|:prob:`10` |:c-d:`0010` | | | |:js-d:`0010`|:py-d:`0010`|:rs-d:`0010`| +|:prob:`10` |:c-d:`0010` | |:cs-d:`0010`| |:js-d:`0010`|:py-d:`0010`|:rs-d:`0010`| +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`11` |:c-d:`0011` |:cp-d:`0011`|:cs-d:`0011`|:ja-d:`0011`|:js-d:`0011`|:py-d:`0011`|:rs-d:`0011`| +-----------+------------+------------+------------+------------+------------+------------+------------+ diff --git a/docs/src/csharp/lib/prime.rst b/docs/src/csharp/lib/prime.rst new file mode 100644 index 00000000..8920b144 --- /dev/null +++ b/docs/src/csharp/lib/prime.rst @@ -0,0 +1,39 @@ +prime.cs +======== + +View source code :source:`csharp/include/prime.cs` + +Includes +-------- + +.. csharp:namespace:: Euler + +.. csharp:class:: Prime + + .. csharp:method:: static IEnumerable Primes(T? stop = null) + + This function implements the `Sieve of Eratosthenes `_. In general, + it will iterate over all of the prime numbers. You can also provide an optional ``stop`` argument, which will force + it to not yield any numbers above that limit. Below is a gif (courtesy of Wikipedia) that demonstrates the principle + of the sieve. + + .. image:: https://upload.wikimedia.org/wikipedia/commons/9/94/Animation_Sieve_of_Eratosth.gif + :alt: Any animated example of the Sieve of Eratosthenes + + .. csharp:method:: static IEnumerable PrimeFactors(T n) + + This function will iterate over all the prime factors of a number, as well as ``-1`` and ``0`` if relevant. + + .. csharp:method:: static dynamic isComposite(long n) + + Returns ``0`` if the number is prime, and the smallest prime factor otherwise. + + .. csharp:method:: static bool isPrime(dynamic n) + + Returns ``true`` if the number is prime, and ``false`` otherwise. + +.. literalinclude:: ../../../../csharp/Euler/include/prime.cs + :language: csharp + :linenos: + +.. tags:: csharp-iterator, prime-number diff --git a/docs/src/csharp/p0003.rst b/docs/src/csharp/p0003.rst index cd40e119..1eff1bdc 100644 --- a/docs/src/csharp/p0003.rst +++ b/docs/src/csharp/p0003.rst @@ -15,4 +15,4 @@ View source code :source:`csharp/Euler/p0003.cs` :language: csharp :linenos: -.. tags:: fibonacci-number, divisibility +.. tags:: prime-number, factorization, csharp-iterator diff --git a/docs/src/csharp/p0007.rst b/docs/src/csharp/p0007.rst new file mode 100644 index 00000000..6a38f284 --- /dev/null +++ b/docs/src/csharp/p0007.rst @@ -0,0 +1,18 @@ +C# Implementation of Problem 7 +============================== + +View source code :source:`csharp/Euler/p0007.cs` + +.. csharp:namespace:: Euler + +.. csharp:class:: p0007 + + .. csharp:inherits:: Euler.IEuler + + .. csharp:method:: object Answer() + +.. literalinclude:: ../../../csharp/Euler/p0007.cs + :language: csharp + :linenos: + +.. tags:: prime-number, csharp-iterator diff --git a/docs/src/csharp/p0010.rst b/docs/src/csharp/p0010.rst new file mode 100644 index 00000000..e5d1b1a2 --- /dev/null +++ b/docs/src/csharp/p0010.rst @@ -0,0 +1,18 @@ +C# Implementation of Problem 10 +=============================== + +View source code :source:`csharp/Euler/p0010.cs` + +.. csharp:namespace:: Euler + +.. csharp:class:: p0010 + + .. csharp:inherits:: Euler.IEuler + + .. csharp:method:: object Answer() + +.. literalinclude:: ../../../csharp/Euler/p0010.cs + :language: csharp + :linenos: + +.. tags:: prime-number, csharp-iterator