diff --git a/README.rst b/README.rst index 859d118a..356b3245 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+ | 18 | |C#i| |br| | +| C# | .NET 2+ | 19 | |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 f457c254..9e584414 100644 --- a/csharp/Euler.Test/test.cs +++ b/csharp/Euler.Test/test.cs @@ -10,6 +10,7 @@ public static IEnumerable Data() yield return new object[] { typeof(p0000), false, 0 }; yield return new object[] { typeof(p0001), false, Utilities.GetAnswer(1) }; yield return new object[] { typeof(p0002), false, Utilities.GetAnswer(2) }; + 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(p0008), false, Utilities.GetAnswer(8) }; @@ -58,6 +59,38 @@ public void EulerTest_Mathematics_Factorial() } } + [Fact] + public void EulerTest_Prime_Primes() + { + List results = new() { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 + }; + var comparison = Prime.Primes().GetEnumerator(); + for (byte i = 0; i < results.Count; i += 1) + { + long expected = results[i]; + comparison.MoveNext(); + Assert.Equal(expected, comparison.Current); + } + } + + [Fact] + 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 y in candidates) + { + List result = new(Prime.PrimeFactors(x * y)); + Assert.Contains(x, result); + Assert.Contains(y, result); + } + } + } + [Fact] public async Task EulerTest_Mathematics_NChooseR() { diff --git a/csharp/Euler/include/prime.cs b/csharp/Euler/include/prime.cs new file mode 100644 index 00000000..190289ca --- /dev/null +++ b/csharp/Euler/include/prime.cs @@ -0,0 +1,141 @@ +using System; + +namespace Euler +{ + public static class Prime + { + private static long lastCached = 0; + private static List cache = new(); + + public static IEnumerable Primes(long? stop = null) + { + if (stop is null) + { + foreach (var p in cache) + { + yield return p; + } + } + else + { + foreach (var p in cache) + { + if (p < stop) + yield return p; + else + break; + } + } + if (stop is not null && lastCached > stop) + yield break; + foreach (var p in ModifiedEratosthenes()) + { + if (p <= lastCached) + continue; + if (stop is not null && p > stop) + break; + cache.Add(p); + lastCached = p; + yield return p; + } + } + + private static IEnumerable ModifiedEratosthenes() + { + yield return 2; + yield return 3; + yield return 5; + yield return 7; + Dictionary sieve = new(); + var recurse = ModifiedEratosthenes().GetEnumerator(); + recurse.MoveNext(); + recurse.MoveNext(); + long prime = recurse.Current; + if (prime != 3) + throw new Exception(); + long primeSquared = prime * prime; + long step = 2; + for (long candidate = 9; ; candidate += 2) + { + if (sieve.ContainsKey(candidate)) + { + step = sieve[candidate]; + sieve.Remove(candidate); + } + else if (candidate < primeSquared) + { + yield return candidate; + continue; + } + else + { + step = prime * 2; + recurse.MoveNext(); + prime = recurse.Current; + primeSquared = prime * prime; + } + long tc = candidate; + do + { + tc += step; + } while (sieve.ContainsKey(tc)); + sieve.Add(tc, step); + } + } + + public static IEnumerable PrimeFactors(long n) + { + if (n < 0) + { + yield return -1; + n = -n; + } + if (n == 0) + { + yield return 0; + } + else + { + long root = (long)Math.Ceiling(Math.Sqrt(n)); + foreach (long factor in Primes()) + { + long modulo = n % factor; + if (modulo == 0) + { + do + { + yield return factor; + n /= factor; + modulo = n % factor; + } while (modulo == 0); + root = (long)Math.Ceiling(Math.Sqrt(n)); + } + if (n <= 1) + break; + if (factor > root) + { + yield return n; + break; + } + } + } + } + + public static long isComposite(long n) + { + var factors = PrimeFactors(n).GetEnumerator(); + factors.MoveNext(); + long first = factors.current; + if (first == n) + return 0; + return first; + } + + public static bool isPrime(long n) + { + if (n < 2) + return false; + return isComposite(n) == 0; + } + } +} diff --git a/csharp/Euler/include/primes.cs b/csharp/Euler/include/primes.cs deleted file mode 100644 index e69de29b..00000000 diff --git a/csharp/Euler/p0003.cs b/csharp/Euler/p0003.cs new file mode 100644 index 00000000..8b3dc36a --- /dev/null +++ b/csharp/Euler/p0003.cs @@ -0,0 +1,24 @@ +/* +Project Euler Problem 3 + +More lazy functions this time. Took a little while to figure out how to +eliminate the special case for 2. + +Problem: + +The prime factors of 13195 are 5, 7, 13 and 29. + +What is the largest prime factor of the number 600851475143 ? +*/ +using System; + +namespace Euler +{ + public class p0003 : IEuler + { + public object Answer() + { + return (short)Enumerable.Max(Prime.PrimeFactors(600851475143)); + } + } +} diff --git a/csharp/README.rst b/csharp/README.rst index 1c8fb106..7805e24a 100644 --- a/csharp/README.rst +++ b/csharp/README.rst @@ -78,6 +78,7 @@ Problems Solved - ☒ `1 <./Euler/p0001.cs>`__ - ☒ `2 <./Euler/p0002.cs>`__ +- ☒ `3 <./Euler/p0003.cs>`__ - ☒ `4 <./Euler/p0004.cs>`__ - ☒ `6 <./Euler/p0006.cs>`__ - ☒ `8 <./Euler/p0008.cs>`__ diff --git a/docs/index.rst b/docs/index.rst index 15b58dc4..62c48580 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -80,7 +80,7 @@ Problems Solved +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`2` |:c-d:`0002` |:cp-d:`0002`|:cs-d:`0002`|:ja-d:`0002`|:js-d:`0002`|:py-d:`0002`|:rs-d:`0002`| +-----------+------------+------------+------------+------------+------------+------------+------------+ -|:prob:`3` |:c-d:`0003` | | | |:js-d:`0003`|:py-d:`0003`|:rs-d:`0003`| +|:prob:`3` |:c-d:`0003` | |:cs-d:`0003`| |:js-d:`0003`|:py-d:`0003`|:rs-d:`0003`| +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`4` |:c-d:`0004` |:cp-d:`0004`|:cs-d:`0004`|:ja-d:`0004`|:js-d:`0004`|:py-d:`0004`|:rs-d:`0004`| +-----------+------------+------------+------------+------------+------------+------------+------------+ diff --git a/docs/src/csharp/lib/csharp.rst b/docs/src/csharp/lib/csharp.rst new file mode 100644 index 00000000..82134ad4 --- /dev/null +++ b/docs/src/csharp/lib/csharp.rst @@ -0,0 +1,29 @@ +prime.cs +======== + +View source code :source:`csharp/include/prime.cs` + +.. csharp:namespace:: Euler + +.. csharp:class:: Prime + + .. csharp:method:: static IEnumerable Primes(long? stop = null) + + Iterate over the prime numbers, optionally stopping before the specified value. Primes are cached between + calls so we don't waste effort. + + .. csharp:method:: static IEnumerable PrimeFactors(long n) + + Iterate over the prime factors of a number (but also ``-1`` and ``0`` in some cases). + + .. csharp:method:: static long isComposite(long n) + + Returns ``0`` if the given number is prime, and otherwise returns its smallest prime factor. + + .. csharp:method:: static bool isPrime(long n) + + Returns ``true`` if a number is prime, and ``false`` otherwise. + +.. literalinclude:: ../../../../csharp/Euler/include/prime.cs + :language: csharp + :linenos: diff --git a/docs/src/csharp/p0003.rst b/docs/src/csharp/p0003.rst new file mode 100644 index 00000000..cd40e119 --- /dev/null +++ b/docs/src/csharp/p0003.rst @@ -0,0 +1,18 @@ +C# Implementation of Problem 3 +============================== + +View source code :source:`csharp/Euler/p0003.cs` + +.. csharp:namespace:: Euler + +.. csharp:class:: p0003 + + .. csharp:inherits:: Euler.IEuler + + .. csharp:method:: object Answer() + +.. literalinclude:: ../../../csharp/Euler/p0003.cs + :language: csharp + :linenos: + +.. tags:: fibonacci-number, divisibility