通过 Eratosthenes Sieve C# 生成素数
Generate Prime Numbers via Eratosthene's Sieve C#
我正在尝试解决 Project Euler 的问题 3,发现 here. I would like to solve it by generating a List of Primes using Eratosthene's Sieve (found here. 我离完成问题还差得很远,但我 运行 遇到了一个小问题...
下面是我为此编写的代码。但是,当我 运行 这段代码时,它会停止我的计算机,并在进一步停止之前输出 2。显然是 运行ning,但它似乎并没有做对。在它输出列表之前,它应该让我知道(只是检查挂起是否在输出之前)它已经完成分配列表...
如果你不确定发生了什么,你能给我一些指导来深入研究代码并调试它的不同行吗?我在不同的地方试过 Console.WriteLine,但它似乎没有响应代码。
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
static void Main(string[] args)
{
long maxNum = 100;
double maxSqrt = Math.Floor(Math.Sqrt(maxNum));
long basePrime;
// Make a list from 2 to maxNum
List<long> numberList = new List<long>();
List<long> sievedList = new List<long>();
for (long i = 2; i <= maxNum; i++) numberList.Add(i);
// Evaluate the first number of the list, if it is < maxSqrt skip it, create a list of multiples and Except them from numberList, else, numberList is completely Prime Factors
foreach (long number in numberList.Skip(1))
{
basePrime = numberList[0];
Console.WriteLine(basePrime);
while (number < maxSqrt)
{
if (number % basePrime == 0)
{
sievedList.Add(number);
}
numberList = numberList.Except(sievedList).ToList();
sievedList.Clear();
}
}
Console.WriteLine("Finished Allocating Primes");
numberList.ForEach(Console.WriteLine);
}
}
对于您眼前的问题,请将 while
更改为 if
。
但是你的代码还有其他问题。
- 您的
numberedList
只是一个从 2 到 maxNum
的整数列表,您正在使用 for 循环填充这些整数。然后你遍历列表。只需使用 for 循环中的计数器即可。为了记录哪些数字是质数,BitArray(Int32, Boolean) 效果很好。
- 这也允许摆脱昂贵的 LINQ 扩展。当您找到一个非质数时,只需更改它在 BitArray 中的索引即可。当您找到质数时,将其添加到列表中;
灵感来自:
Laziness in Python - Computerphile
我将其翻译成 C#:
using System;
using System.Collections.Generic;
using System.Linq;
namespace GenertatorTest
{
class Program
{
/// <summary>
/// Natural Numbers Genarator
/// </summary>
/// <param name="first">first number in the sequence</param>
/// <returns>the sequence: first, first + 1, first + 2, ... ∞</returns>
static IEnumerable<int> natural(int begin)
{
yield return begin;
foreach (var item in natural(begin + 1))
{
yield return item;
}
}
/// <summary>
/// Primary Numbers Genarator
/// </summary>
/// <param name="nums">natural numbers sequence which we want to apply Eratosthene's Sieve on</param>
/// <returns>infinite primary numbers sequence</returns>
static IEnumerable<int> primes(IEnumerable<int> nums)
{
int p = nums.ElementAt(0);
yield return p;
foreach (var item in primes(nums.Where(x => x % p != 0)))
{
yield return item;
}
}
static void Main(string[] args)
{
foreach (var item in primes(natural(2)))
{
Console.WriteLine(item);
//it is infinite sequence
//so you cant just run through.
Console.ReadKey();
}
}
}
}
其实这段代码比你想象的要优雅。我们这里唯一缺少的语法糖是 yield from
,C# 似乎不支持它。
我正在尝试解决 Project Euler 的问题 3,发现 here. I would like to solve it by generating a List of Primes using Eratosthene's Sieve (found here. 我离完成问题还差得很远,但我 运行 遇到了一个小问题...
下面是我为此编写的代码。但是,当我 运行 这段代码时,它会停止我的计算机,并在进一步停止之前输出 2。显然是 运行ning,但它似乎并没有做对。在它输出列表之前,它应该让我知道(只是检查挂起是否在输出之前)它已经完成分配列表...
如果你不确定发生了什么,你能给我一些指导来深入研究代码并调试它的不同行吗?我在不同的地方试过 Console.WriteLine,但它似乎没有响应代码。
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
static void Main(string[] args)
{
long maxNum = 100;
double maxSqrt = Math.Floor(Math.Sqrt(maxNum));
long basePrime;
// Make a list from 2 to maxNum
List<long> numberList = new List<long>();
List<long> sievedList = new List<long>();
for (long i = 2; i <= maxNum; i++) numberList.Add(i);
// Evaluate the first number of the list, if it is < maxSqrt skip it, create a list of multiples and Except them from numberList, else, numberList is completely Prime Factors
foreach (long number in numberList.Skip(1))
{
basePrime = numberList[0];
Console.WriteLine(basePrime);
while (number < maxSqrt)
{
if (number % basePrime == 0)
{
sievedList.Add(number);
}
numberList = numberList.Except(sievedList).ToList();
sievedList.Clear();
}
}
Console.WriteLine("Finished Allocating Primes");
numberList.ForEach(Console.WriteLine);
}
}
对于您眼前的问题,请将 while
更改为 if
。
但是你的代码还有其他问题。
- 您的
numberedList
只是一个从 2 到maxNum
的整数列表,您正在使用 for 循环填充这些整数。然后你遍历列表。只需使用 for 循环中的计数器即可。为了记录哪些数字是质数,BitArray(Int32, Boolean) 效果很好。 - 这也允许摆脱昂贵的 LINQ 扩展。当您找到一个非质数时,只需更改它在 BitArray 中的索引即可。当您找到质数时,将其添加到列表中;
灵感来自: Laziness in Python - Computerphile 我将其翻译成 C#:
using System;
using System.Collections.Generic;
using System.Linq;
namespace GenertatorTest
{
class Program
{
/// <summary>
/// Natural Numbers Genarator
/// </summary>
/// <param name="first">first number in the sequence</param>
/// <returns>the sequence: first, first + 1, first + 2, ... ∞</returns>
static IEnumerable<int> natural(int begin)
{
yield return begin;
foreach (var item in natural(begin + 1))
{
yield return item;
}
}
/// <summary>
/// Primary Numbers Genarator
/// </summary>
/// <param name="nums">natural numbers sequence which we want to apply Eratosthene's Sieve on</param>
/// <returns>infinite primary numbers sequence</returns>
static IEnumerable<int> primes(IEnumerable<int> nums)
{
int p = nums.ElementAt(0);
yield return p;
foreach (var item in primes(nums.Where(x => x % p != 0)))
{
yield return item;
}
}
static void Main(string[] args)
{
foreach (var item in primes(natural(2)))
{
Console.WriteLine(item);
//it is infinite sequence
//so you cant just run through.
Console.ReadKey();
}
}
}
}
其实这段代码比你想象的要优雅。我们这里唯一缺少的语法糖是 yield from
,C# 似乎不支持它。