Skip to content
Browse files

Problems 64-69, lots of refactoring

  • Loading branch information...
1 parent 5ad40e8 commit 2925c426ade3aaddac052ea117e7e69a6cd95c5e unknown committed
Showing with 4,166 additions and 159 deletions.
  1. +1 −0 .gitignore
  2. +32 −0 Ckknight.ProjectEuler.sln
  3. BIN Ckknight.ProjectEuler.suo
  4. +6 −0 Ckknight.ProjectEuler.vsmdi
  5. +237 −0 Ckknight.ProjectEuler/BigContinuedFraction.cs
  6. +624 −0 Ckknight.ProjectEuler/BigFraction.cs
  7. +13 −1 Ckknight.ProjectEuler/Ckknight.ProjectEuler.csproj
  8. +13 −0 Ckknight.ProjectEuler/CollectionUtilities.cs
  9. +80 −0 Ckknight.ProjectEuler/Collections/BetterCombinationGenerator.cs
  10. +20 −3 Ckknight.ProjectEuler/Collections/BooleanArray.cs
  11. +292 −0 Ckknight.ProjectEuler/Collections/DefaultDictionary.cs
  12. +121 −0 Ckknight.ProjectEuler/Collections/EnumerableExtensions.cs
  13. +7 −10 Ckknight.ProjectEuler/Collections/FactorGenerator.cs
  14. +12 −0 Ckknight.ProjectEuler/Collections/ImmutableSequence.cs
  15. +209 −14 Ckknight.ProjectEuler/Collections/Int32Set.cs
  16. +1 −1 Ckknight.ProjectEuler/Collections/PrimeFactorGenerator.cs
  17. +159 −99 Ckknight.ProjectEuler/Collections/PrimeGenerator.cs
  18. +251 −0 Ckknight.ProjectEuler/ContinuedFraction.cs
  19. +639 −0 Ckknight.ProjectEuler/Fraction.cs
  20. +99 −7 Ckknight.ProjectEuler/MathUtilities.cs
  21. +1 −1 Ckknight.ProjectEuler/Problems/Problem005.cs
  22. +1 −1 Ckknight.ProjectEuler/Problems/Problem007.cs
  23. +1 −1 Ckknight.ProjectEuler/Problems/Problem010.cs
  24. +2 −2 Ckknight.ProjectEuler/Problems/Problem027.cs
  25. +2 −2 Ckknight.ProjectEuler/Problems/Problem035.cs
  26. +2 −2 Ckknight.ProjectEuler/Problems/Problem037.cs
  27. +1 −1 Ckknight.ProjectEuler/Problems/Problem041.cs
  28. +2 −2 Ckknight.ProjectEuler/Problems/Problem046.cs
  29. +3 −3 Ckknight.ProjectEuler/Problems/Problem049.cs
  30. +2 −2 Ckknight.ProjectEuler/Problems/Problem050.cs
  31. +1 −1 Ckknight.ProjectEuler/Problems/Problem051.cs
  32. +1 −1 Ckknight.ProjectEuler/Problems/Problem058.cs
  33. +3 −3 Ckknight.ProjectEuler/Problems/Problem060.cs
  34. +1 −1 Ckknight.ProjectEuler/Problems/Problem062.cs
  35. +108 −0 Ckknight.ProjectEuler/Problems/Problem064.cs
  36. +79 −0 Ckknight.ProjectEuler/Problems/Problem065.cs
  37. +46 −0 Ckknight.ProjectEuler/Problems/Problem066.cs
  38. +81 −0 Ckknight.ProjectEuler/Problems/Problem067.cs
  39. +79 −0 Ckknight.ProjectEuler/Problems/Problem068.cs
  40. +45 −0 Ckknight.ProjectEuler/Problems/Problem069.cs
  41. +1 −1 Ckknight.ProjectEuler/Program.cs
  42. +62 −0 Ckknight.ProjectEulerTest/BigSqrtTest.cs
  43. +69 −0 Ckknight.ProjectEulerTest/Ckknight.ProjectEulerTest.csproj
  44. +20 −0 Ckknight.ProjectEulerTest/CombinationGeneratorTest.cs
  45. +94 −0 Ckknight.ProjectEulerTest/ContinuedFractionTest.cs
  46. +563 −0 Ckknight.ProjectEulerTest/FractionTest.cs
  47. +35 −0 Ckknight.ProjectEulerTest/Properties/AssemblyInfo.cs
  48. BIN Ckknight.ProjectEulerTest/bin/Debug/Ckknight.ProjectEuler.exe
  49. BIN Ckknight.ProjectEulerTest/bin/Debug/Ckknight.ProjectEuler.pdb
  50. BIN Ckknight.ProjectEulerTest/bin/Debug/Ckknight.ProjectEulerTest.dll
  51. BIN Ckknight.ProjectEulerTest/bin/Debug/Ckknight.ProjectEulerTest.pdb
  52. +14 −0 Ckknight.ProjectEulerTest/obj/Debug/Ckknight.ProjectEulerTest.csproj.FileListAbsolute.txt
  53. BIN Ckknight.ProjectEulerTest/obj/Debug/Ckknight.ProjectEulerTest.dll
  54. BIN Ckknight.ProjectEulerTest/obj/Debug/Ckknight.ProjectEulerTest.pdb
  55. BIN Ckknight.ProjectEulerTest/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
  56. BIN Ckknight.ProjectEulerTest/obj/Debug/ResolveAssemblyReference.cache
  57. +10 −0 Local.testsettings
  58. +21 −0 TraceAndTestImpact.testsettings
View
1 .gitignore
@@ -0,0 +1 @@
+TestResults/
View
32 Ckknight.ProjectEuler.sln
@@ -3,16 +3,48 @@ Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ckknight.ProjectEuler", "Ckknight.ProjectEuler\Ckknight.ProjectEuler.csproj", "{A212B257-6D17-4912-8084-A2B4E9974F62}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ckknight.ProjectEulerTest", "Ckknight.ProjectEulerTest\Ckknight.ProjectEulerTest.csproj", "{45091873-82CF-4F03-A431-4547655C67DD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{611436E3-AF14-4B14-B94F-266F6FA45CA9}"
+ ProjectSection(SolutionItems) = preProject
+ Ckknight.ProjectEuler.vsmdi = Ckknight.ProjectEuler.vsmdi
+ Local.testsettings = Local.testsettings
+ TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
+ EndProjectSection
+EndProject
Global
+ GlobalSection(TestCaseManagementSettings) = postSolution
+ CategoryFile = Ckknight.ProjectEuler.vsmdi
+ EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A212B257-6D17-4912-8084-A2B4E9974F62}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {A212B257-6D17-4912-8084-A2B4E9974F62}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+ {A212B257-6D17-4912-8084-A2B4E9974F62}.Debug|Mixed Platforms.Build.0 = Debug|x86
{A212B257-6D17-4912-8084-A2B4E9974F62}.Debug|x86.ActiveCfg = Debug|x86
{A212B257-6D17-4912-8084-A2B4E9974F62}.Debug|x86.Build.0 = Debug|x86
+ {A212B257-6D17-4912-8084-A2B4E9974F62}.Release|Any CPU.ActiveCfg = Release|x86
+ {A212B257-6D17-4912-8084-A2B4E9974F62}.Release|Mixed Platforms.ActiveCfg = Release|x86
+ {A212B257-6D17-4912-8084-A2B4E9974F62}.Release|Mixed Platforms.Build.0 = Release|x86
{A212B257-6D17-4912-8084-A2B4E9974F62}.Release|x86.ActiveCfg = Release|x86
{A212B257-6D17-4912-8084-A2B4E9974F62}.Release|x86.Build.0 = Release|x86
+ {45091873-82CF-4F03-A431-4547655C67DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {45091873-82CF-4F03-A431-4547655C67DD}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
View
BIN Ckknight.ProjectEuler.suo
Binary file not shown.
View
6 Ckknight.ProjectEuler.vsmdi
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
+ <TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
+ <RunConfiguration id="ee51332a-2095-4e7d-83c4-431590abb05b" name="Local" storage="local.testsettings" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+ </TestList>
+</TestLists>
View
237 Ckknight.ProjectEuler/BigContinuedFraction.cs
@@ -0,0 +1,237 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Numerics;
+
+namespace Ckknight.ProjectEuler.Collections
+{
+ public class BigContinuedFraction
+ {
+ private BigContinuedFraction(BigInteger floor, IEnumerable<BigInteger> nonPeriodicQuotients, IEnumerable<BigInteger> periodicQuotients)
+ {
+ _floor = floor;
+ _nonPeriodicQuotients = nonPeriodicQuotients ?? Enumerable.Empty<BigInteger>();
+ _periodicQuotients = periodicQuotients ?? Enumerable.Empty<BigInteger>();
+ }
+
+ public BigContinuedFraction(BigInteger floor)
+ : this(floor, default(IEnumerable<BigInteger>), default(IEnumerable<BigInteger>)) { }
+
+ public BigContinuedFraction(BigInteger floor, IEnumerable<BigInteger> nonPeriodicQuotients)
+ : this(floor, nonPeriodicQuotients, default(IEnumerable<BigInteger>))
+ {
+ if (nonPeriodicQuotients == null)
+ {
+ throw new ArgumentNullException("nonPeriodicQuotients");
+ }
+ }
+
+ public BigContinuedFraction(BigInteger floor, IEnumerable<BigInteger> nonPeriodicQuotients, BigInteger[] periodicQuotients)
+ : this(floor, nonPeriodicQuotients, (IEnumerable<BigInteger>)periodicQuotients)
+ {
+ if (nonPeriodicQuotients == null)
+ {
+ throw new ArgumentNullException("nonPeriodicQuotients");
+ }
+ else if (periodicQuotients == null)
+ {
+ throw new ArgumentNullException("periodicQuotients");
+ }
+ }
+
+ public static readonly BigContinuedFraction Zero = new BigContinuedFraction(0);
+ public static readonly BigContinuedFraction One = new BigContinuedFraction(1);
+
+ private readonly BigInteger _floor;
+ public BigInteger Floor
+ {
+ get
+ {
+ return _floor;
+ }
+ }
+
+ private readonly IEnumerable<BigInteger> _nonPeriodicQuotients;
+ public IEnumerable<BigInteger> NonPeriodicQuotients
+ {
+ get
+ {
+ return _nonPeriodicQuotients;
+ }
+ }
+
+ private readonly IEnumerable<BigInteger> _periodicQuotients;
+ public IEnumerable<BigInteger> PeriodicQuotients
+ {
+ get
+ {
+ return _periodicQuotients;
+ }
+ }
+
+ public IEnumerable<BigInteger> Quotients
+ {
+ get
+ {
+ foreach (BigInteger quotient in _nonPeriodicQuotients)
+ {
+ yield return quotient;
+ }
+
+ while (true)
+ {
+ bool found = false;
+ foreach (BigInteger quotient in _periodicQuotients)
+ {
+ if (!found)
+ {
+ found = true;
+ }
+ yield return quotient;
+ }
+ if (!found)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ private const int MaxNonPeriodicLengthShown = 10;
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append('[');
+ sb.Append(_floor);
+
+ BigInteger[] partialNonPeriodicQuotients = _nonPeriodicQuotients as BigInteger[];
+ if (partialNonPeriodicQuotients == null)
+ {
+ partialNonPeriodicQuotients = _nonPeriodicQuotients.Take(MaxNonPeriodicLengthShown + 1).ToArray();
+ }
+ int length = partialNonPeriodicQuotients.Length;
+ if (length > MaxNonPeriodicLengthShown)
+ {
+ length = MaxNonPeriodicLengthShown;
+ }
+ for (int i = 0; i < length; i++)
+ {
+ if (i == 0)
+ {
+ sb.Append("; ");
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.Append(partialNonPeriodicQuotients[i]);
+ }
+ if (partialNonPeriodicQuotients.Length > MaxNonPeriodicLengthShown)
+ {
+ sb.Append(", ...");
+ }
+
+ BigInteger[] periodicQuotients = _periodicQuotients as BigInteger[] ?? _periodicQuotients.ToArray();
+ if (periodicQuotients.Length > 0)
+ {
+ if (length == 0)
+ {
+ sb.Append("; ");
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.Append('(');
+ for (int i = 0; i < periodicQuotients.Length; i++)
+ {
+ if (i > 0)
+ {
+ sb.Append(", ");
+ }
+ sb.Append(periodicQuotients[i]);
+ }
+ sb.Append(')');
+ }
+
+ sb.Append(']');
+ return sb.ToString();
+ }
+
+ public static BigContinuedFraction Sqrt(BigInteger value)
+ {
+ BigInteger sqrt = MathUtilities.BigSqrt(value);
+
+ if (sqrt * sqrt == value)
+ {
+ return new BigContinuedFraction(sqrt);
+ }
+ else
+ {
+ var period = CollectionUtilities.Repeat(default(object))
+ .SelectWithAggregate(new { m = BigInteger.Zero, d = BigInteger.One, a = sqrt }, (x, i) =>
+ {
+ BigInteger m = x.d * x.a - x.m;
+ BigInteger d = (value - m * m) / x.d;
+ BigInteger a = (sqrt + m) / d;
+ return new { m, d, a };
+ })
+ .TakeWhileDistinct()
+ .Select(x => x.a)
+ .ToArray();
+
+ return new BigContinuedFraction(sqrt, Enumerable.Empty<BigInteger>(), period);
+ }
+ }
+
+ public static BigContinuedFraction FromBigFraction(BigFraction fraction)
+ {
+ if (fraction.Denominator.IsZero)
+ {
+ throw new ArithmeticException("Cannot generate continued fraction from NaN, Infinity, or -Infinity");
+ }
+
+ bool first = true;
+ BigInteger initial = BigInteger.Zero;
+ List<BigInteger> quotients = new List<BigInteger>();
+ while (true)
+ {
+ BigFraction remainder;
+ BigInteger floor = BigFraction.DivRem(fraction, BigFraction.One, out remainder).Numerator;
+
+ if (first)
+ {
+ first = false;
+ initial = floor;
+ }
+ else
+ {
+ quotients.Add(floor);
+ }
+
+ if (remainder.IsZero)
+ {
+ return new BigContinuedFraction(initial, quotients.ToArray());
+ }
+
+ fraction = BigFraction.Reciprocal(remainder);
+ }
+ }
+
+ public IEnumerable<BigFraction> GetBigFractions()
+ {
+ return this.Quotients
+ .PrependItem(this.Floor)
+ .SelectWithAggregate(new { Alpha = BigFraction.Zero, Bravo = BigFraction.PositiveInfinity }, (x, v) =>
+ new
+ {
+ Alpha = x.Bravo,
+ Bravo = new BigFraction(
+ v * x.Bravo.Numerator + x.Alpha.Numerator,
+ v * x.Bravo.Denominator + x.Alpha.Denominator)
+ })
+ .Select(x => x.Bravo);
+ }
+ }
+}
View
624 Ckknight.ProjectEuler/BigFraction.cs
@@ -0,0 +1,624 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Numerics;
+
+namespace Ckknight.ProjectEuler
+{
+ public struct BigFraction : IComparable<BigFraction>, IEquatable<BigFraction>
+ {
+ public BigFraction(BigInteger numerator)
+ : this(numerator, 1) { }
+
+ public BigFraction(BigInteger numerator, BigInteger denominator)
+ {
+ if (denominator == 0)
+ {
+ _numerator = numerator.Sign;
+ _denominator = 0;
+ }
+ else if (numerator == 0)
+ {
+ _numerator = 0;
+ _denominator = 1;
+ }
+ else
+ {
+ BigInteger gcd = BigInteger.GreatestCommonDivisor(numerator, denominator);
+
+ if (!gcd.IsOne)
+ {
+ numerator /= gcd;
+ denominator /= gcd;
+ }
+
+ if (denominator < 0)
+ {
+ numerator = -numerator;
+ denominator = -denominator;
+ }
+ _numerator = numerator;
+ _denominator = denominator;
+ }
+ }
+
+ private readonly BigInteger _numerator;
+ private readonly BigInteger _denominator;
+
+ public BigInteger Numerator
+ {
+ get
+ {
+ return _numerator;
+ }
+ }
+
+ public BigInteger Denominator
+ {
+ get
+ {
+ return _denominator;
+ }
+ }
+
+ public bool IsZero
+ {
+ get
+ {
+ return _numerator.IsZero && !_denominator.IsZero;
+ }
+ }
+
+ public bool IsOne
+ {
+ get
+ {
+ return _numerator.IsOne && _denominator.IsOne;
+ }
+ }
+
+ public bool IsInteger
+ {
+ get
+ {
+ return _denominator.IsOne;
+ }
+ }
+
+ public bool IsNaN
+ {
+ get
+ {
+ return _denominator.IsZero && _numerator.IsZero;
+ }
+ }
+
+ public bool IsPositiveInfinity
+ {
+ get
+ {
+ return _denominator.IsZero && _numerator.Sign > 0;
+ }
+ }
+
+ public bool IsNegativeInfinity
+ {
+ get
+ {
+ return _denominator.IsZero && _numerator.Sign < 0;
+ }
+ }
+
+ public int Sign
+ {
+ get
+ {
+ if (IsNaN)
+ {
+ throw new ArithmeticException("This BigFraction is not a number");
+ }
+ else
+ {
+ return _numerator.Sign;
+ }
+ }
+ }
+
+ public static readonly BigFraction NaN = default(BigFraction);
+ public static readonly BigFraction PositiveInfinity = new BigFraction(1, 0);
+ public static readonly BigFraction NegativeInfinity = new BigFraction(-1, 0);
+ public static readonly BigFraction Zero = new BigFraction(0);
+ public static readonly BigFraction One = new BigFraction(1);
+
+ public override string ToString()
+ {
+ if (_denominator == 0)
+ {
+ if (_numerator == 0)
+ {
+ return "NaN";
+ }
+ else if (_numerator > 0)
+ {
+ return "Infinity";
+ }
+ else
+ {
+ return "-Infinity";
+ }
+ }
+ else if (IsZero)
+ {
+ return "0";
+ }
+ else if (IsInteger)
+ {
+ return _numerator.ToString();
+ }
+ else
+ {
+ return string.Format("{0}/{1}", _numerator, _denominator);
+ }
+ }
+
+ public bool Equals(BigFraction other)
+ {
+ return this._numerator.Equals(other._numerator) && this._denominator.Equals(other._denominator);
+ }
+
+ public override bool Equals(object other)
+ {
+ if (other == null)
+ {
+ return false;
+ }
+ else if (other is BigFraction)
+ {
+ return Equals((BigFraction)other);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return _numerator.GetHashCode() ^ _denominator.GetHashCode();
+ }
+
+ public int CompareTo(BigFraction other)
+ {
+ if (this.Equals(other))
+ {
+ return 0;
+ }
+ else if (this.IsNaN)
+ {
+ return -1;
+ }
+ else if (other.IsNaN)
+ {
+ return 1;
+ }
+ else if (this.IsNegativeInfinity)
+ {
+ return -1;
+ }
+ else if (other.IsNegativeInfinity)
+ {
+ return 1;
+ }
+ else if (this.IsPositiveInfinity)
+ {
+ return 1;
+ }
+ else if (other.IsPositiveInfinity)
+ {
+ return -1;
+ }
+ else
+ {
+ BigFraction difference = this - other;
+
+ return difference.Sign;
+ }
+ }
+
+ public static BigFraction Pow(BigFraction number, long exponent)
+ {
+ if (number.IsNaN)
+ {
+ return BigFraction.NaN;
+ }
+ else if (number.IsZero)
+ {
+ return BigFraction.Zero;
+ }
+ else if (exponent == 0L)
+ {
+ return BigFraction.One;
+ }
+ else if (number.IsNegativeInfinity)
+ {
+ if ((exponent & 1L) != 0L)
+ {
+ return BigFraction.NegativeInfinity;
+ }
+ else
+ {
+ return BigFraction.PositiveInfinity;
+ }
+ }
+ else if (number.IsPositiveInfinity)
+ {
+ return BigFraction.PositiveInfinity;
+ }
+ else if (exponent == 1L)
+ {
+ return number;
+ }
+ else if (exponent == 2L)
+ {
+ return number * number;
+ }
+ else if (exponent < 0L)
+ {
+ throw new ArgumentOutOfRangeException("exponent", exponent, "Must be at least 0");
+ }
+
+ BigFraction result = BigFraction.One;
+ while (exponent != 0L)
+ {
+ if ((exponent & 1L) != 0L)
+ {
+ result *= number;
+ }
+ exponent >>= 1;
+ number *= number;
+ }
+
+ return result;
+ }
+
+ public static BigFraction Floor(BigFraction number)
+ {
+ if (number._denominator == 0 || number.IsInteger)
+ {
+ return number;
+ }
+ else
+ {
+ return new BigFraction((number._numerator - (number._numerator % number._denominator)) / number._denominator, 1);
+ }
+ }
+
+ public static BigFraction Ceiling(BigFraction number)
+ {
+ if (number._denominator == 0 || number.IsInteger)
+ {
+ return number;
+ }
+ else
+ {
+ return new BigFraction((number._numerator - (number._numerator % number._denominator)) / number._denominator + 1, 1);
+ }
+ }
+
+ public static BigFraction Abs(BigFraction number)
+ {
+ if (number._numerator >= 0)
+ {
+ return number;
+ }
+ else
+ {
+ return -number;
+ }
+ }
+
+ public static double Log(BigFraction number, double baseValue)
+ {
+ if (number._denominator == 0)
+ {
+ if (number._numerator > 0)
+ {
+ return double.PositiveInfinity;
+ }
+ else
+ {
+ return double.NaN;
+ }
+ }
+ else if (number._numerator == 0)
+ {
+ return double.NegativeInfinity;
+ }
+ else
+ {
+ return BigInteger.Log(number._numerator, baseValue) - BigInteger.Log(number._denominator, baseValue);
+ }
+ }
+
+ public static double Log(BigFraction number)
+ {
+ return Log(number, Math.E);
+ }
+
+ public static double Log10(BigFraction number)
+ {
+ return Log(number, 10.0);
+ }
+
+ public static BigFraction operator *(BigFraction multiplicand, BigFraction multiplier)
+ {
+ if (multiplicand._denominator == 0 || multiplier._denominator == 0)
+ {
+ int sign = multiplicand._numerator.Sign * multiplier._numerator.Sign;
+ if (sign == 0)
+ {
+ return BigFraction.NaN;
+ }
+ else if (sign < 0)
+ {
+ return BigFraction.NegativeInfinity;
+ }
+ else
+ {
+ return BigFraction.PositiveInfinity;
+ }
+ }
+ else
+ {
+ return new BigFraction(multiplicand._numerator * multiplier._numerator, multiplicand._denominator * multiplier._denominator);
+ }
+ }
+
+ public static BigFraction Reciprocal(BigFraction number)
+ {
+ return new BigFraction(number._denominator, number._numerator);
+ }
+
+ public static BigFraction operator /(BigFraction dividend, BigFraction divisor)
+ {
+ return dividend * BigFraction.Reciprocal(divisor);
+ }
+
+ public static BigFraction operator %(BigFraction dividend, BigFraction divisor)
+ {
+ BigFraction remainder;
+ DivRem(dividend, divisor, out remainder);
+ return remainder;
+ }
+
+ public static BigFraction DivRem(BigFraction dividend, BigFraction divisor, out BigFraction remainder)
+ {
+ if (divisor._denominator == 0)
+ {
+ if (divisor._numerator == 0 || dividend._denominator == 0)
+ {
+ remainder = BigFraction.NaN;
+ return BigFraction.NaN;
+ }
+ else
+ {
+ remainder = dividend;
+ return BigFraction.Zero;
+ }
+ }
+ else
+ {
+ if (divisor.IsOne)
+ {
+ BigFraction quotient = BigFraction.Floor(dividend);
+ remainder = dividend - quotient;
+ return quotient;
+ }
+ else
+ {
+ BigFraction quotient = BigFraction.Floor(dividend / divisor);
+ remainder = dividend - (quotient * divisor);
+ return quotient;
+ }
+ }
+ }
+
+ public static BigFraction operator +(BigFraction augend, BigFraction addend)
+ {
+ if (augend._denominator == 0)
+ {
+ if (augend._numerator == 0)
+ {
+ return BigFraction.NaN;
+ }
+ else if (augend._numerator < 0)
+ {
+ if (addend._denominator == 0 && addend._numerator >= 0)
+ {
+ return BigFraction.NaN;
+ }
+ else
+ {
+ return BigFraction.NegativeInfinity;
+ }
+ }
+ else
+ {
+ if (addend._denominator == 0 && addend._numerator <= 0)
+ {
+ return BigFraction.NaN;
+ }
+ else
+ {
+ return BigFraction.PositiveInfinity;
+ }
+ }
+ }
+ else if (addend._denominator == 0)
+ {
+ return addend;
+ }
+ else
+ {
+ return new BigFraction(augend._numerator * addend._denominator + augend._denominator * addend._numerator, augend._denominator * addend._denominator);
+ }
+ }
+
+ public static BigFraction operator -(BigFraction minuend, BigFraction subtrahend)
+ {
+ return minuend + (-subtrahend);
+ }
+
+ public static BigFraction operator +(BigFraction number)
+ {
+ return number;
+ }
+
+ public static BigFraction operator -(BigFraction number)
+ {
+ return new BigFraction(-number._numerator, number._denominator);
+ }
+
+ public static bool operator ==(BigFraction alpha, BigFraction bravo)
+ {
+ return alpha.Equals(bravo);
+ }
+
+ public static bool operator !=(BigFraction alpha, BigFraction bravo)
+ {
+ return !alpha.Equals(bravo);
+ }
+
+ public static bool operator <(BigFraction alpha, BigFraction bravo)
+ {
+ return alpha.CompareTo(bravo) < 0;
+ }
+
+ public static bool operator >(BigFraction alpha, BigFraction bravo)
+ {
+ return alpha.CompareTo(bravo) > 0;
+ }
+
+ public static bool operator <=(BigFraction alpha, BigFraction bravo)
+ {
+ return alpha.CompareTo(bravo) <= 0;
+ }
+
+ public static bool operator >=(BigFraction alpha, BigFraction bravo)
+ {
+ return alpha.CompareTo(bravo) >= 0;
+ }
+
+ public static implicit operator BigFraction(Fraction number)
+ {
+ return new BigFraction(number.Numerator, number.Denominator);
+ }
+
+ public static implicit operator BigFraction(BigInteger number)
+ {
+ return new BigFraction(number);
+ }
+
+ public static implicit operator BigFraction(long number)
+ {
+ return new BigFraction(number, 1);
+ }
+
+ public static implicit operator BigFraction(int number)
+ {
+ return new BigFraction(number, 1);
+ }
+
+ public static explicit operator BigInteger(BigFraction value)
+ {
+ return value._numerator / value._denominator;
+ }
+
+ public static explicit operator ulong(BigFraction value)
+ {
+ return (ulong)((BigInteger)value);
+ }
+
+ public static explicit operator long(BigFraction value)
+ {
+ return (long)((BigInteger)value);
+ }
+
+ public static explicit operator uint(BigFraction value)
+ {
+ return (uint)((BigInteger)value);
+ }
+
+ public static explicit operator int(BigFraction value)
+ {
+ return (int)((BigInteger)value);
+ }
+
+ public static explicit operator ushort(BigFraction value)
+ {
+ return (ushort)((BigInteger)value);
+ }
+
+ public static explicit operator short(BigFraction value)
+ {
+ return (short)((BigInteger)value);
+ }
+
+ public static explicit operator byte(BigFraction value)
+ {
+ return (byte)((BigInteger)value);
+ }
+
+ public static explicit operator sbyte(BigFraction value)
+ {
+ return (sbyte)((BigInteger)value);
+ }
+
+ public static explicit operator decimal(BigFraction value)
+ {
+ return (decimal)value._numerator / (decimal)value._denominator;
+ }
+
+ public static explicit operator double(BigFraction value)
+ {
+ return Math.Exp(BigFraction.Log(value));
+ }
+
+ public static explicit operator float(BigFraction value)
+ {
+ return (float)((double)value);
+ }
+
+ public static explicit operator BigFraction(double number)
+ {
+ if (number == double.NaN)
+ {
+ return BigFraction.NaN;
+ }
+ else
+ {
+ int power = 0;
+ while (number % 1.0 != 0.0)
+ {
+ number *= 2;
+ power++;
+ }
+
+ return new BigFraction((BigInteger)number, BigInteger.Pow(2, power));
+ }
+ }
+
+ public static explicit operator BigFraction(decimal number)
+ {
+ int power = 0;
+ while (number % 1m != 0m)
+ {
+ number *= 10m;
+ power++;
+ }
+
+ return new BigFraction((BigInteger)number, BigInteger.Pow(10, power));
+ }
+ }
+}
View
14 Ckknight.ProjectEuler/Ckknight.ProjectEuler.csproj
@@ -44,9 +44,15 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="BigFraction.cs" />
+ <Compile Include="BigContinuedFraction.cs" />
+ <Compile Include="Collections\BetterCombinationGenerator.cs" />
<Compile Include="Collections\BooleanArray.cs" />
<Compile Include="Collections\BooleanMatrix.cs" />
+ <Compile Include="Collections\PrimeGenerator.cs" />
<Compile Include="Collections\CombinationGenerator.cs" />
+ <Compile Include="Collections\DefaultDictionary.cs" />
+ <Compile Include="ContinuedFraction.cs" />
<Compile Include="Collections\EnumerableExtensions.cs" />
<Compile Include="Collections\FactorGenerator.cs" />
<Compile Include="Collections\FibonacciSequence.cs" />
@@ -57,9 +63,9 @@
<Compile Include="Collections\MultiHashSet.cs" />
<Compile Include="Collections\PermutationGenerator.cs" />
<Compile Include="Collections\PrimeFactorGenerator.cs" />
- <Compile Include="Collections\PrimeGenerator.cs" />
<Compile Include="Collections\Range.cs" />
<Compile Include="CollectionUtilities.cs" />
+ <Compile Include="Fraction.cs" />
<Compile Include="MathUtilities.cs" />
<Compile Include="ObjectExtensions.cs" />
<Compile Include="Problems\BaseProblem.cs" />
@@ -126,6 +132,12 @@
<Compile Include="Problems\Problem061.cs" />
<Compile Include="Problems\Problem062.cs" />
<Compile Include="Problems\Problem063.cs" />
+ <Compile Include="Problems\Problem064.cs" />
+ <Compile Include="Problems\Problem065.cs" />
+ <Compile Include="Problems\Problem066.cs" />
+ <Compile Include="Problems\Problem067.cs" />
+ <Compile Include="Problems\Problem068.cs" />
+ <Compile Include="Problems\Problem069.cs" />
<Compile Include="Problems\ProblemAttribute.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
View
13 Ckknight.ProjectEuler/CollectionUtilities.cs
@@ -27,6 +27,11 @@ public static HashSet<T> EmptyHashSet<T>(Func<T> typeCreator)
return new HashSet<T>();
}
+ public static Dictionary<TKey, TValue> EmptyDictionary<TKey, TValue>(Func<TKey> keyTypeCreator, Func<TValue> valueTypeCreator)
+ {
+ return new Dictionary<TKey, TValue>();
+ }
+
public static List<T> NewList<T>(params T[] args)
{
return new List<T>(args);
@@ -81,5 +86,13 @@ public int GetHashCode(IEnumerable<T> obj)
return hashCode;
}
}
+
+ public static IEnumerable<T> Repeat<T>(T item)
+ {
+ while (true)
+ {
+ yield return item;
+ }
+ }
}
}
View
80 Ckknight.ProjectEuler/Collections/BetterCombinationGenerator.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+
+namespace Ckknight.ProjectEuler.Collections
+{
+ public class BetterCombinationGenerator<T> : IEnumerable<T[]>
+ {
+ /// <summary>
+ /// Initialize a new CombinationGenerator based on the conditions.
+ /// </summary>
+ /// <param name="source">The source enumerable to pull data from.</param>
+ /// <param name="amount">The size of each combination.</param>
+ public BetterCombinationGenerator(IEnumerable<T> source, int amount)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException("source");
+ }
+ else if (amount < 0)
+ {
+ throw new ArgumentOutOfRangeException("amount", amount, "Must be at least 0");
+ }
+
+ _source = source;
+ _amount = amount;
+ }
+
+ private readonly IEnumerable<T> _source;
+ private readonly int _amount;
+
+ /// <summary>
+ /// Return an enumerator which iterates over all combinations.
+ /// </summary>
+ /// <returns>The combination enumerator.</returns>
+ public IEnumerator<T[]> GetEnumerator()
+ {
+ if (_amount == 0)
+ {
+ return Enumerable.Empty<T[]>()
+ .GetEnumerator();
+ }
+ else if (_amount == 1)
+ {
+ return _source
+ .Select(x => new[] { x })
+ .GetEnumerator();
+ }
+ else
+ {
+ T[] array = _source as T[] ?? _source.ToArray();
+
+ int length = array.Length;
+ if (_amount > length)
+ {
+ return Enumerable.Empty<T[]>()
+ .GetEnumerator();
+ }
+
+ return new Range(_amount)
+ .Aggregate(new List<ImmutableSequence<int>> { ImmutableSequence<int>.Empty }.AsEnumerable(),
+ (x, i) => x
+ .SelectMany(seq => new Range(seq.HasValue ? seq.First() + 1 : 0, length - _amount + i, true)
+ .Select(n => new ImmutableSequence<int>(n, seq))))
+ .Select(s => s
+ .Reverse()
+ .Select(i => array[i])
+ .ToArray())
+ .GetEnumerator();
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.GetEnumerator();
+ }
+ }
+}
View
23 Ckknight.ProjectEuler/Collections/BooleanArray.cs
@@ -9,13 +9,24 @@ namespace Ckknight.ProjectEuler.Collections
public class BooleanArray : IList<bool>, IList
{
public BooleanArray(int length)
+ : this(length, false) { }
+
+ public BooleanArray(int length, bool defaultValue)
{
if (length < 0)
{
throw new ArgumentOutOfRangeException("length", length, "Must be at least 0");
}
_length = length;
- _data = new byte[GetDataLength(length)];
+ int dataLength = GetDataLength(length);
+ _data = new byte[dataLength];
+ if (defaultValue)
+ {
+ for (int i = 0; i < dataLength; i++)
+ {
+ _data[i] = 255;
+ }
+ }
}
public BooleanArray(BooleanArray source)
@@ -337,7 +348,7 @@ void ICollection.CopyTo(Array array, int index)
}
}
- public bool IsSynchronized
+ bool ICollection.IsSynchronized
{
get
{
@@ -345,12 +356,18 @@ public bool IsSynchronized
}
}
- public object SyncRoot
+ object ICollection.SyncRoot
{
get
{
return this;
}
}
+
+ public ParallelQuery<bool> AsParallel()
+ {
+ return ParallelEnumerable.Range(0, _length)
+ .Select(i => this[i]);
+ }
}
}
View
292 Ckknight.ProjectEuler/Collections/DefaultDictionary.cs
@@ -0,0 +1,292 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+
+namespace Ckknight.ProjectEuler.Collections
+{
+ public class DefaultDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary
+ {
+ public DefaultDictionary(Func<TKey, TValue> populator)
+ : this(populator, null, null) { }
+
+ public DefaultDictionary(Func<TKey, TValue> populator, IDictionary<TKey, TValue> dictionary)
+ : this(populator, dictionary, null) { }
+
+ public DefaultDictionary(Func<TKey, TValue> populator, IEqualityComparer<TKey> comparer)
+ : this(populator, null, comparer) { }
+
+ public DefaultDictionary(Func<TKey, TValue> populator, IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
+ {
+ if (dictionary == null)
+ {
+ _data = new Dictionary<TKey, TValue>(comparer);
+ }
+ else
+ {
+ _data = new Dictionary<TKey, TValue>(dictionary, comparer);
+ }
+ _populator = populator;
+ }
+
+ private readonly Dictionary<TKey, TValue> _data;
+ private readonly Func<TKey, TValue> _populator;
+
+ public void Add(TKey key, TValue value)
+ {
+ _data.Add(key, value);
+ }
+
+ public bool ContainsKey(TKey key)
+ {
+ return true;
+ }
+
+ public ICollection<TKey> Keys
+ {
+ get
+ {
+ return _data.Keys;
+ }
+ }
+
+ public bool Remove(TKey key)
+ {
+ _data.Remove(key);
+ return true;
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ if (_data.TryGetValue(key, out value))
+ {
+ return true;
+ }
+ else
+ {
+ _data[key] = value = _populator(key);
+ return true;
+ }
+ }
+
+ public ICollection<TValue> Values
+ {
+ get
+ {
+ return _data.Values;
+ }
+ }
+
+ public TValue this[TKey key]
+ {
+ get
+ {
+ TValue value;
+ TryGetValue(key, out value);
+ return value;
+ }
+ set
+ {
+ _data[key] = value;
+ }
+ }
+
+ void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
+ {
+ Add(item.Key, item.Value);
+ }
+
+ public void Clear()
+ {
+ _data.Clear();
+ }
+
+ bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
+ {
+ TValue value;
+ TryGetValue(item.Key, out value);
+ return object.Equals(item.Value, value);
+ }
+
+ void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ {
+ ((ICollection<KeyValuePair<TKey, TValue>>)_data).CopyTo(array, arrayIndex);
+ }
+
+ public int Count
+ {
+ get
+ {
+ return _data.Count;
+ }
+ }
+
+ bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
+ {
+ TValue value;
+ TryGetValue(item.Key, out value);
+ if (object.Equals(item.Value, value))
+ {
+ _data.Remove(item.Key);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+ {
+ return _data.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.GetEnumerator();
+ }
+
+ void IDictionary.Add(object key, object value)
+ {
+ if (!(key is TKey))
+ {
+ throw new ArgumentException(string.Format("Must be a {0}", typeof(TKey)), "key");
+ }
+ else if (!(value is TValue))
+ {
+ throw new ArgumentException(string.Format("Must be a {0}", typeof(TValue)), "value");
+ }
+
+ Add((TKey)key, (TValue)value);
+ }
+
+ bool IDictionary.Contains(object key)
+ {
+ if (key is TKey)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ IDictionaryEnumerator IDictionary.GetEnumerator()
+ {
+ return ((IDictionary)_data).GetEnumerator();
+ }
+
+ bool IDictionary.IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ bool IDictionary.IsFixedSize
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ ICollection IDictionary.Keys
+ {
+ get
+ {
+ return ((IDictionary)_data).Keys;
+ }
+ }
+
+ public void Remove(object key)
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException("key");
+ }
+
+ if (key is TKey)
+ {
+ _data.Remove((TKey)key);
+ }
+ }
+
+ ICollection IDictionary.Values
+ {
+ get
+ {
+ return ((IDictionary)_data).Values;
+ }
+ }
+
+ object IDictionary.this[object key]
+ {
+ get
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException("key");
+ }
+
+ if (!(key is TKey))
+ {
+ return null;
+ }
+ else
+ {
+ return this[(TKey)key];
+ }
+ }
+ set
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException("key");
+ }
+ else if (!(key is TKey))
+ {
+ throw new ArgumentException(string.Format("Must be a {0}", typeof(TKey)), "key");
+ }
+ else if (!(value is TValue))
+ {
+ throw new ArgumentException(string.Format("Must be a {0}", typeof(TValue)), "value");
+ }
+
+ this[(TKey)key] = (TValue)value;
+ }
+ }
+
+ void ICollection.CopyTo(Array array, int index)
+ {
+ ((ICollection)_data).CopyTo(array, index);
+ }
+
+ bool ICollection.IsSynchronized
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ object ICollection.SyncRoot
+ {
+ get
+ {
+ return _data;
+ }
+ }
+ }
+}
View
121 Ckknight.ProjectEuler/Collections/EnumerableExtensions.cs
@@ -697,5 +697,126 @@ public static IEnumerable<T> AppendItem<T>(this IEnumerable<T> sequence, T item)
.Where(x => x.HasValue)
.Select(x => x.Value);
}
+
+ public static IEnumerable<T> TakeWhileDistinct<T>(this IEnumerable<T> sequence)
+ {
+ return TakeWhileDistinct(sequence, false);
+ }
+
+ public static IEnumerable<T> TakeWhileDistinct<T>(this IEnumerable<T> sequence, bool includeLast)
+ {
+ if (sequence == null)
+ {
+ throw new ArgumentNullException("sequence");
+ }
+
+ HashSet<T> set = new HashSet<T>();
+ foreach (T item in sequence)
+ {
+ if (set.Contains(item))
+ {
+ if (includeLast)
+ {
+ yield return item;
+ }
+ yield break;
+ }
+
+ yield return item;
+ set.Add(item);
+ }
+ }
+
+ public static TElement WithMax<TElement, TValue>(this IEnumerable<TElement> sequence, Func<TElement, TValue> selector)
+ {
+ if (sequence == null)
+ {
+ throw new ArgumentNullException("sequence");
+ }
+ else if (selector == null)
+ {
+ throw new ArgumentNullException("selector");
+ }
+
+ IComparer<TValue> comparer = Comparer<TValue>.Default;
+
+ return sequence
+ .Select(e => new
+ {
+ Element = e,
+ Value = selector(e)
+ })
+ .Aggregate((a, b) => comparer.Compare(a.Value, b.Value) >= 0 ? a : b)
+ .Element;
+ }
+
+ public static TElement WithMin<TElement, TValue>(this IEnumerable<TElement> sequence, Func<TElement, TValue> selector)
+ {
+ if (sequence == null)
+ {
+ throw new ArgumentNullException("sequence");
+ }
+ else if (selector == null)
+ {
+ throw new ArgumentNullException("selector");
+ }
+
+ IComparer<TValue> comparer = Comparer<TValue>.Default;
+
+ return sequence
+ .Select(e => new
+ {
+ Element = e,
+ Value = selector(e)
+ })
+ .Aggregate((a, b) => comparer.Compare(a.Value, b.Value) <= 0 ? a : b)
+ .Element;
+ }
+
+ public static TElement WithMax<TElement, TValue>(this ParallelQuery<TElement> sequence, Func<TElement, TValue> selector)
+ {
+ if (sequence == null)
+ {
+ throw new ArgumentNullException("sequence");
+ }
+ else if (selector == null)
+ {
+ throw new ArgumentNullException("selector");
+ }
+
+ IComparer<TValue> comparer = Comparer<TValue>.Default;
+
+ return sequence
+ .Select(e => new
+ {
+ Element = e,
+ Value = selector(e)
+ })
+ .Aggregate((a, b) => comparer.Compare(a.Value, b.Value) >= 0 ? a : b)
+ .Element;
+ }
+
+ public static TElement WithMin<TElement, TValue>(this ParallelQuery<TElement> sequence, Func<TElement, TValue> selector)
+ {
+ if (sequence == null)
+ {
+ throw new ArgumentNullException("sequence");
+ }
+ else if (selector == null)
+ {
+ throw new ArgumentNullException("selector");
+ }
+
+ IComparer<TValue> comparer = Comparer<TValue>.Default;
+
+ return sequence
+ .Select(e => new
+ {
+ Element = e,
+ Value = selector(e)
+ })
+ .Aggregate((a, b) => comparer.Compare(a.Value, b.Value) <= 0 ? a : b)
+ .Element;
+ }
}
}
View
17 Ckknight.ProjectEuler/Collections/FactorGenerator.cs
@@ -31,16 +31,13 @@ public IEnumerator<long> GetEnumerator()
{
long[] primeFactors = new PrimeFactorGenerator(_number).ToArray();
- HashSet<long> divisors = new HashSet<long> { 1L };
- int max = primeFactors.Length;
- if (_includeNumber)
- {
- max++;
- }
- for (int i = 1; i < max; i++)
- {
- divisors.UnionWith(primeFactors.GetCombinations(i).Select(x => x.Product()));
- }
+ var divisors = new Range(primeFactors.Length)
+ .Aggregate(new HashSet<long> { 1L }, (x, i) =>
+ {
+ long primeFactor = primeFactors[i];
+ x.UnionWith(x.Select(v => v * primeFactor).ToArray());
+ return x;
+ });
return divisors.GetEnumerator();
}
View
12 Ckknight.ProjectEuler/Collections/ImmutableSequence.cs
@@ -138,6 +138,18 @@ public ImmutableSequence<T> Skip(int amount)
}
}
+ public IEnumerable<T> Reverse()
+ {
+ Stack<T> data = new Stack<T>();
+ ImmutableSequence<T> current = this;
+ while (current._hasValue)
+ {
+ data.Push(current._head);
+ current = current._tail ?? Empty;
+ }
+ return data;
+ }
+
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
View
223 Ckknight.ProjectEuler/Collections/Int32Set.cs
@@ -11,7 +11,7 @@ namespace Ckknight.ProjectEuler.Collections
///
/// This is meant to be very fast for adding, removing, and checking to see whether an Int32 is contained.
/// </summary>
- public class Int32Set : ICollection<int>
+ public class Int32Set : ISet<int>, ICollection<int>
{
public Int32Set(int capacity)
{
@@ -20,7 +20,7 @@ public Int32Set(int capacity)
throw new ArgumentOutOfRangeException("capacity", capacity, "Must be at least 0");
}
_capacity = capacity;
- _bucket = new BitArray(capacity);
+ _bucket = new BooleanArray(capacity);
}
public Int32Set(IEnumerable<int> sequence, int capacity)
@@ -42,7 +42,7 @@ public Int32Set(IEnumerable<int> sequence, int capacity)
}
private readonly int _capacity;
- private readonly BitArray _bucket;
+ private readonly BooleanArray _bucket;
public int Capacity
{
@@ -65,18 +65,9 @@ public IEnumerable<int> GetInverse()
#region ICollection<int> Members
- public void Add(int item)
+ void ICollection<int>.Add(int item)
{
- if (item < 0)
- {
- throw new ArgumentOutOfRangeException("item", item, "Must be at least 0");
- }
- else if (item >= _capacity)
- {
- throw new ArgumentOutOfRangeException("item", item, string.Format("Must be at most {0}", _capacity - 1));
- }
-
- _bucket[item] = true;
+ Add(item);
}
public void Clear()
@@ -151,6 +142,12 @@ public bool Remove(int item)
#endregion
+ public ParallelQuery<int> AsParallel()
+ {
+ return ParallelEnumerable.Range(0, _capacity)
+ .Where(i => _bucket[i]);
+ }
+
#region IEnumerable<int> Members
public IEnumerator<int> GetEnumerator()
@@ -174,5 +171,203 @@ IEnumerator IEnumerable.GetEnumerator()
}
#endregion
+
+ public bool Add(int item)
+ {
+ if (item < 0)
+ {
+ throw new ArgumentOutOfRangeException("item", item, "Must be at least 0");
+ }
+ else if (item >= _capacity)
+ {
+ throw new ArgumentOutOfRangeException("item", item, string.Format("Must be at most {0}", _capacity - 1));
+ }
+
+ if (_bucket[item])
+ {
+ return false;
+ }
+ else
+ {
+ _bucket[item] = true;
+ return true;
+ }
+ }
+
+ public void ExceptWith(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+ foreach (int item in other)
+ {
+ _bucket[item] = false;
+ }
+ }
+
+ public void IntersectWith(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+ ISet<int> otherSet = other as ISet<int> ?? other.ToHashSet();
+ foreach (int item in this)
+ {
+ if (!otherSet.Contains(item))
+ {
+ _bucket[item] = false;
+ }
+ }
+ }
+
+ public bool IsProperSubsetOf(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+
+ ISet<int> otherSet = other as ISet<int> ?? other.ToHashSet();
+ foreach (int item in this)
+ {
+ if (!otherSet.Contains(item))
+ {
+ return false;
+ }
+ }
+ foreach (int item in otherSet)
+ {
+ if (!Contains(item))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool IsProperSupersetOf(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+
+ ISet<int> otherSet = other as ISet<int> ?? other.ToHashSet();
+ foreach (int item in otherSet)
+ {
+ if (!Contains(item))
+ {
+ return false;
+ }
+ }
+
+ foreach (int item in this)
+ {
+ if (!otherSet.Contains(item))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool IsSubsetOf(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+
+ ISet<int> otherSet = other as ISet<int> ?? other.ToHashSet();
+ foreach (int item in this)
+ {
+ if (!otherSet.Contains(item))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public bool IsSupersetOf(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+
+ foreach (int item in other)
+ {
+ if (!Contains(item))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public bool Overlaps(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+
+ foreach (int item in other)
+ {
+ if (Contains(item))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool SetEquals(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+
+ var otherSet = other.ToHashSet();
+ foreach (int item in this)
+ {
+ if (!otherSet.Contains(item))
+ {
+ return false;
+ }
+ otherSet.Remove(item);
+ }
+ return otherSet.Count == 0;
+ }
+
+ public void SymmetricExceptWith(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+
+ foreach (int item in other.Distinct())
+ {
+ _bucket[item] = !_bucket[item];
+ }
+ }
+
+ public void UnionWith(IEnumerable<int> other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException("other");
+ }
+
+ foreach (int item in other)
+ {
+ _bucket[item] = true;
+ }
+ }
}
}
View
2 Ckknight.ProjectEuler/Collections/PrimeFactorGenerator.cs
@@ -42,7 +42,7 @@ public IEnumerator<long> GetEnumerator()
long remainingNumber = _number;
long midpoint = (long)(Math.Sqrt(_number));
- foreach (long prime in new PrimeGenerator())
+ foreach (long prime in PrimeGenerator.Instance)
{
if (prime > midpoint)
{
View
258 Ckknight.ProjectEuler/Collections/PrimeGenerator.cs
@@ -1,158 +1,218 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
-using System.Collections;
+using System.Collections.Concurrent;
namespace Ckknight.ProjectEuler.Collections
{
- /// <summary>
- /// Represents an enumerable which generates primes.
- /// </summary>
- public sealed class PrimeGenerator : IEnumerable<long>
+ public class PrimeGenerator : IEnumerable<long>, IEnumerable
{
- private static readonly List<long> _foundPrimes = new List<long>
+ private PrimeGenerator()
{
- 2,
- 3,
- 5,
- 7,
- 11,
- 13,
- 17,
- 19,
- 23,
- 29,
- };
- private static readonly HashSet<long> _primeSet = new HashSet<long>(_foundPrimes);
- private static int _calculatedPrimesUpTo = 30;
+ }
- /// <summary>
- /// Return whether a given value is prime.
- /// </summary>
- /// <param name="value">The value to check for primeness.</param>
- /// <returns>Whether the value is prime.</returns>
- public static bool IsPrime(long value)
+ private static readonly PrimeGenerator _instance = new PrimeGenerator();
+ public static PrimeGenerator Instance
{
- if (_primeSet.Contains(value))
+ get
{
- return true;
+ return _instance;
}
- else if (value <= _calculatedPrimesUpTo)
+ }
+
+ private long _calculatedUpTo = 1;
+ private const int StandardPrimeCalculationChunkSize = 10000;
+ private const int MaxPrimeCalculationChunkSize = 8000000;
+ private readonly List<long> _primes = new List<long>();
+ private readonly HashSet<long> _primeSet = new HashSet<long>();
+
+ public void CalculateUpTo(long value)
+ {
+ if (value % StandardPrimeCalculationChunkSize != 0)
{
- return false;
+ value += StandardPrimeCalculationChunkSize - (value % StandardPrimeCalculationChunkSize);
}
+ long start = _calculatedUpTo;
- long sqrt = (long)Math.Sqrt(value);
- foreach (long i in new PrimeGenerator().TakeWhile(x => x <= sqrt))
+ for (long i = _calculatedUpTo + 1; i < value; i += MaxPrimeCalculationChunkSize)
{
- if ((value % i) == 0L)
+ long max = i + MaxPrimeCalculationChunkSize;
+ if (max > value)
{
- return false;
+ max = value;
}
+ CalculatePrimes(i, (int)(max - i));
}
- return true;
- }
-
- /// <summary>
- /// Get the prime at the 0-based index of all primes.
- /// </summary>
- /// <param name="index">The 0-based index to get the prime of.</param>
- /// <returns>The prime at the given index.</returns>
- public static long GetPrimeAtIndex(int index)
- {
- while (_foundPrimes.Count <= index)
- {
- GetNextSection();
- }
-
- return _foundPrimes[index];
}
- public static void CalculateUpTo(int maximum)
+ public void CalculateNextChuck()
{
- while (_calculatedPrimesUpTo < maximum)
- {
- GetNextSection();
- }
+ CalculatePrimes(_calculatedUpTo + 1, StandardPrimeCalculationChunkSize);
}
- private static readonly int[] _numbersToCheck = new Range(30).ToArray();
-
- private static IEnumerable<long> GetNextSection()
+ private readonly object _syncRoot = new object();
+ private void CalculatePrimes(long start, int length)
{
- List<long> tmp = new List<long>();
-
- while (tmp.Count == 0)
+ long max = start + length - 1;
+ if (max > _calculatedUpTo)
{
- for (int i = 0; i < _numbersToCheck.Length; i++)
+ lock (_syncRoot)
{
- long value = _calculatedPrimesUpTo + _numbersToCheck[i];
- bool isComposite = false;
- long midpoint = (long)Math.Sqrt(value);
- foreach (long prime in _foundPrimes)
+ if (max > _calculatedUpTo)
{
- if (prime > midpoint)
+ BooleanArray data = new BooleanArray(length);
+
+ long maxValue = (long)Math.Ceiling(Math.Sqrt(length + start));
+
+ for (int i = 0; i < _primes.Count; i++)
{
- break;
+ long value = _primes[i];
+ if (value > maxValue)
+ {
+ break;
+ }
+
+ long iterStart = (value * value) - start;
+ if (iterStart < 0)
+ {
+ iterStart -= value * (iterStart / value);
+ if (start % value != 0)
+ {
+ iterStart += value;
+ }
+ }
+ for (long j = iterStart; j < length; j += value)
+ {
+ data[(int)j] = true;
+ }
}
- if ((value % prime) == 0)
+
+ for (int i = 0; i < length; i++)
{
- isComposite = true;
- break;
+ if (!data[i])
+ {
+ long value = start + i;
+ _primes.Add(value);
+ _primeSet.Add(value);
+
+ if (value <= maxValue)
+ {
+ for (long j = ((value * value) - start); j < length; j += value)
+ {
+ data[(int)j] = true;
+ }
+ }
+ }
}
+ _calculatedUpTo = max;
}
- if (!isComposite)
+ }
+ }
+ }
+
+ public IEnumerator<long> GetEnumerator()
+ {
+ int index = 0;
+
+ while (true)
+ {
+ long count;
+ do
+ {
+ count = _primes.Count;
+ for (; index < count; index++)
{
- _foundPrimes.Add(value);
- _primeSet.Add(value);
- tmp.Add(value);
+ long prime = _primes[index];
+ yield return prime;
}
- }
- _calculatedPrimesUpTo += _numbersToCheck.Length;
+ } while (count < _primes.Count);
+
+ CalculateNextChuck();
}
+ }
- return tmp;
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.GetEnumerator();
}
- #region IEnumerable<long> Members
+ /// <summary>
+ /// Get the prime at the 0-based index of all primes.
+ /// </summary>
+ /// <param name="index">The 0-based index to get the prime of.</param>
+ /// <returns>The prime at the given index.</returns>
+ public long GetPrimeAtIndex(int index)
+ {
+ if (_primes.Count > index)
+ {
+ return _primes[index];
+ }
+
+ if (index > 6)
+ {
+ double log = Math.Log(index);
+ long approximatePrimeValue = (long)Math.Floor(index * log + index * Math.Log(log));
+ CalculateUpTo(approximatePrimeValue);
+ }
+
+ while (_primes.Count <= index)
+ {
+ CalculateNextChuck();
+ }
+
+ return _primes[index];
+ }
/// <summary>
- /// Return an enumerator which iterates over all primes.
+ /// Return whether a given value is prime.
/// </summary>
- /// <returns>The enumerator of primes.</returns>
- public IEnumerator<long> GetEnumerator()
+ /// <param name="value">The value to check for primeness.</param>
+ /// <returns>Whether the value is prime.</returns>
+ public bool IsPrime(long value)
{
- // we need to yield all the primes we have previously found.
- for (int i = 0; i < _foundPrimes.Count; i++)
+ if (_primeSet.Contains(value))
{
- long prime = _foundPrimes[i];
- yield return prime;
+ return true;
+ }
+ else if (value <= _calculatedUpTo)
+ {
+ return false;
}
- // then we repeatedly get the primes of the next section and yield those values.
- while (true)
+ long sqrt = (long)Math.Sqrt(value);
+ CalculateUpTo(sqrt);
+
+ int count = _primes.Count;
+ for (int i = 0; i < count; i++)
{
- foreach (long value in GetNextSection())
+ long prime = _primes[i];
+ if (prime > sqrt)
{
- yield return value;
+ break;
+ }
+ else if ((value % prime) == 0L)
+ {
+ return false;
}
}
+ _primeSet.Add(value);
+ return true;
}
- #endregion
+ public IEnumerable<long> GetUpTo(long amount)
+ {
+ CalculateUpTo(amount);
- #region IEnumerable Members
+ return this
+ .TakeWhile(n => n <= amount);
+ }
- /// <summary>
- /// Return an enumerator which iterates over all primes.
- /// </summary>
- /// <returns>The enumerator of primes.</returns>
- IEnumerator IEnumerable.GetEnumerator()
+ public ParallelQuery<long> AsParallel(long upToAmount)
{
- return this.GetEnumerator();
+ return Partitioner.Create<long>(GetUpTo(upToAmount))
+ .AsParallel();
}
-
- #endregion
}
}
View
251 Ckknight.ProjectEuler/ContinuedFraction.cs
@@ -0,0 +1,251 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Ckknight.ProjectEuler.Collections;
+
+namespace Ckknight.ProjectEuler
+{
+ public class ContinuedFraction
+ {
+ private ContinuedFraction(long floor, IEnumerable<long> nonPeriodicQuotients, IEnumerable<long> periodicQuotients)
+ {
+ _floor = floor;
+ _nonPeriodicQuotients = nonPeriodicQuotients ?? Enumerable.Empty<long>();
+ _periodicQuotients = periodicQuotients ?? Enumerable.Empty<long>();
+ }
+
+ public ContinuedFraction(long floor)
+ : this(floor, default(IEnumerable<long>), default(IEnumerable<long>)) { }
+
+ public ContinuedFraction(long floor, IEnumerable<long> nonPeriodicQuotients)
+ : this(floor, nonPeriodicQuotients, default(IEnumerable<long>))
+ {
+ if (nonPeriodicQuotients == null)
+ {
+ throw new ArgumentNullException("nonPeriodicQuotients");
+ }
+ }
+
+ public ContinuedFraction(long floor, IEnumerable<long> nonPeriodicQuotients, long[] periodicQuotients)
+ : this(floor, nonPeriodicQuotients, (IEnumerable<long>)periodicQuotients)
+ {
+ if (nonPeriodicQuotients == null)
+ {
+ throw new ArgumentNullException("nonPeriodicQuotients");
+ }
+ else if (periodicQuotients == null)
+ {
+ throw new ArgumentNullException("periodicQuotients");
+ }
+ }
+
+ public static readonly ContinuedFraction Zero = new ContinuedFraction(0);
+ public static readonly ContinuedFraction One = new ContinuedFraction(1);
+
+ private readonly long _floor;
+ public long Floor
+ {
+ get
+ {
+ return _floor;
+ }
+ }
+
+ private readonly IEnumerable<long> _nonPeriodicQuotients;
+ public IEnumerable<long> NonPeriodicQuotients
+ {
+ get
+ {
+ return _nonPeriodicQuotients;
+ }
+ }
+
+ private readonly IEnumerable<long> _periodicQuotients;
+ public IEnumerable<long> PeriodicQuotients
+ {
+ get
+ {
+ return _periodicQuotients;
+ }
+ }
+
+ public IEnumerable<long> Quotients
+ {
+ get
+ {
+ foreach (long quotient in _nonPeriodicQuotients)
+ {
+ yield return quotient;
+ }
+
+ while (true)
+ {
+ bool found = false;
+ foreach (long quotient in _periodicQuotients)
+ {
+ if (!found)
+ {
+ found = true;
+ }
+ yield return quotient;
+ }
+ if (!found)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ private const int MaxNonPeriodicLengthShown = 10;
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append('[');
+ sb.Append(_floor);
+
+ long[] partialNonPeriodicQuotients = _nonPeriodicQuotients as long[];
+ if (partialNonPeriodicQuotients == null)
+ {
+ partialNonPeriodicQuotients = _nonPeriodicQuotients.Take(MaxNonPeriodicLengthShown + 1).ToArray();
+ }
+ int length = partialNonPeriodicQuotients.Length;
+ if (length > MaxNonPeriodicLengthShown)
+ {
+ length = MaxNonPeriodicLengthShown;
+ }
+ for (int i = 0; i < length; i++)
+ {
+ if (i == 0)
+ {
+ sb.Append("; ");
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.Append(partialNonPeriodicQuotients[i]);
+ }
+ if (partialNonPeriodicQuotients.Length > MaxNonPeriodicLengthShown)
+ {
+ sb.Append(", ...");
+ }
+
+ long[] periodicQuotients = _periodicQuotients as long[] ?? _periodicQuotients.ToArray();
+ if (periodicQuotients.Length > 0)
+ {
+ if (length == 0)
+ {
+ sb.Append("; ");
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.Append('(');
+ for (int i = 0; i < periodicQuotients.Length; i++)
+ {
+ if (i > 0)
+ {