Skip to content

Instantly share code, notes, and snippets.

@battermann
Last active August 29, 2015 14:07
Show Gist options
  • Save battermann/b2939d88d00746cea653 to your computer and use it in GitHub Desktop.
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
///<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;
}
}
}
///<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;
}
}
}
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