Last active
August 29, 2015 14:07
-
-
Save battermann/b2939d88d00746cea653 to your computer and use it in GitHub Desktop.
Prime Generator aus Agile Principles, Patterns and Practices in C# von Robert C. Martin refactored nach IOSP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///<remark> | |
/// Refactored Version (following IOSP) | |
///</remark> | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace primegenerator | |
{ | |
public class PrimeGenerator | |
{ | |
public static int[] GeneratePrimeNumbers(int maxValue) | |
{ | |
var crossedOut = new bool[maxValue + 1]; | |
int limit = DetermineIterationLimit(crossedOut); | |
EnumerateFrom2UpTo(limit, i => UncrossMultiplesIfNotCrossed(crossedOut, i)); | |
return DeterminePrimeNumbers(crossedOut); | |
} | |
private static int[] DeterminePrimeNumbers(bool[] crossedOut) | |
{ | |
var result = new List<int>(); | |
EnumerateFrom2UpTo(crossedOut.Length - 1, i => AddPrimeIfNotCrossed(result, crossedOut, i)); | |
return result.ToArray(); | |
} | |
private static void AddPrimeIfNotCrossed(List<int> result, bool[] crossedOut, int i) | |
{ | |
CheckIfCrossed(crossedOut, i, () => result.Add(i)); | |
} | |
private static void UncrossMultiplesIfNotCrossed(bool[] crossedOut, int i) | |
{ | |
CheckIfCrossed(crossedOut, i, () => CrossOutputMultiplesOf(crossedOut, i)); | |
} | |
private static int DetermineIterationLimit(bool[] crossedOut) | |
{ | |
// Every multiple in the array has a prime factor that | |
// is less than or equal to the root of the array size, | |
// so we don't have to cross off multiples of numbers | |
// larger than that root. | |
return (int)Math.Sqrt(crossedOut.Length); | |
} | |
private static void EnumerateFrom2UpTo(int limit, Action<int> continueWith) | |
{ | |
for (int i = 2; i <= limit; i++) | |
continueWith(i); | |
} | |
private static void CheckIfCrossed(bool[] crossedOut, int i, Action onNotCrossed) | |
{ | |
if (crossedOut[i] == false) | |
onNotCrossed(); | |
} | |
private static void CheckMaxValue(int maxValue, Action onGreaterOne) | |
{ | |
if (maxValue > 1) | |
onGreaterOne(); | |
} | |
private static void CrossOutputMultiplesOf(bool[] crossedOut, int i) | |
{ | |
for (int multiple = 2 * i; multiple < crossedOut.Length; multiple += i) | |
crossedOut[multiple] = true; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///<remark> | |
/// Prime Generator by Robert C. Martin from the book "Agile Principles, Patterns and Practices in C#" | |
///</remark> | |
using System; | |
namespace primegenerator | |
{ | |
public class PrimeGeneratorByMartin | |
{ | |
private static bool[] crossedOut; | |
private static int[] result; | |
public static int[] GeneratePrimeNumbers(int maxValue) | |
{ | |
if (maxValue < 2) | |
return new int[0]; | |
else | |
{ | |
UncrossIntegersUpTo(maxValue); | |
CrossOutMultiples(); | |
PutUncrossedIntegersIntoResult(); | |
return result; | |
} | |
} | |
private static void UncrossIntegersUpTo(int maxValue) | |
{ | |
crossedOut = new bool[maxValue + 1]; | |
for (int i = 2; i < crossedOut.Length; i++) | |
crossedOut[i] = false; | |
} | |
private static void PutUncrossedIntegersIntoResult() | |
{ | |
result = new int[NumberOfUncrossedIntegers()]; | |
for (int j = 0, i = 2; i < crossedOut.Length; i++) | |
{ | |
if (NotCrossed(i)) | |
result[j++] = i; | |
} | |
} | |
private static int NumberOfUncrossedIntegers() | |
{ | |
int count = 0; | |
for (int i = 2; i < crossedOut.Length; i++) | |
{ | |
if (NotCrossed(i)) | |
count++; // bump count. | |
} | |
return count; | |
} | |
private static void CrossOutMultiples() | |
{ | |
int limit = DetermineIterationLimit(); | |
for (int i = 2; i <= limit; i++) | |
{ | |
if (NotCrossed(i)) | |
CrossOutputMultiplesOf(i); | |
} | |
} | |
private static int DetermineIterationLimit() | |
{ | |
// Every multiple in the array has a prime factor that | |
// is less than or equal to the root of the array size, | |
// so we don't have to cross off multiples of numbers | |
// larger than that root. | |
double iterationLimit = Math.Sqrt(crossedOut.Length); | |
return (int)iterationLimit; | |
} | |
private static void CrossOutputMultiplesOf(int i) | |
{ | |
for (int multiple = 2 * i; multiple < crossedOut.Length; multiple += i) | |
crossedOut[multiple] = true; | |
} | |
private static bool NotCrossed(int i) | |
{ | |
return crossedOut[i] == false; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using NUnit.Framework; | |
using primegenerator; | |
namespace primegeneratortest | |
{ | |
[TestFixture] | |
public class PrimeGeneratorTests | |
{ | |
[Test] | |
public void TestPrimes() | |
{ | |
int[] nullArray = PrimeGenerator.GeneratePrimeNumbers(0); | |
Assert.AreEqual(nullArray.Length, 0); | |
int[] minArray = PrimeGenerator.GeneratePrimeNumbers(2); | |
Assert.AreEqual(minArray.Length, 1); | |
Assert.AreEqual(minArray[0], 2); | |
int[] threeArray = PrimeGenerator.GeneratePrimeNumbers(3); | |
Assert.AreEqual(threeArray.Length, 2); | |
Assert.AreEqual(threeArray[0], 2); | |
Assert.AreEqual(threeArray[1], 3); | |
int[] centArray = PrimeGenerator.GeneratePrimeNumbers(100); | |
Assert.AreEqual(centArray.Length, 25); | |
Assert.AreEqual(centArray[24], 97); | |
} | |
[Test] | |
public void TestExhaustive() | |
{ | |
for (int i = 2; i < 500; i++) | |
VerifyPrimeList(PrimeGenerator.GeneratePrimeNumbers(i)); | |
} | |
private void VerifyPrimeList(int[] list) | |
{ | |
for (int i = 0; i < list.Length; i++) | |
VerifyPrime(list[i]); | |
} | |
private void VerifyPrime(int n) | |
{ | |
for (int factor = 2; factor < n; factor++) | |
Assert.IsTrue(n % factor != 0); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment