简体   繁体   English

寻找素数的程序

[英]Program to find prime numbers

I want to find the prime number between 0 and a long variable but I am not able to get any output.我想找到 0 和 long 变量之间的质数,但我无法获得任何输出。

The program is该程序是

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication16
{
    class Program
    {
        void prime_num(long num)
        {
            bool isPrime = true;
            for (int i = 0; i <= num; i++)
            {
                for (int j = 2; j <= num; j++)
                {
                    if (i != j && i % j == 0)
                    {
                        isPrime = false;
                        break;
                    }
                }
                if (isPrime)
                {
                    Console.WriteLine ( "Prime:" + i );
                }
                isPrime = true;
            }
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            p.prime_num (999999999999999L);
            Console.ReadLine();
        }
    }
}

Can any one help me out and find what is the possible error in the program?任何人都可以帮我找出程序中可能存在的错误吗?

You can do this faster using a nearly optimal trial division sieve in one (long) line like this:您可以在一条(长)行中使用近乎最佳的试验分割筛来更快地完成此操作,如下所示:

Enumerable.Range(0, Math.Floor(2.52*Math.Sqrt(num)/Math.Log(num))).Aggregate(
    Enumerable.Range(2, num-1).ToList(), 
    (result, index) => { 
        var bp = result[index]; var sqr = bp * bp;
        result.RemoveAll(i => i >= sqr && i % bp == 0); 
        return result; 
    }
);

The approximation formula for number of primes used here is π(x) < 1.26 x / ln(x) .这里使用的素数数量的近似公式是π(x) < 1.26 x / ln(x) We only need to test by primes not greater than x = sqrt(num) .我们只需要通过不大于x = sqrt(num)的素数进行测试。

Note that the sieve of Eratosthenes has much better run time complexity than trial division (should run much faster for bigger num values, when properly implemented).请注意, Eratosthenes筛选具有比试除法更好的运行时间复杂度(如果正确实施,对于更大的num值应该运行得更快)。

Try this:试试这个:

void prime_num(long num)
{

    // bool isPrime = true;
    for (long i = 0; i <= num; i++)
    {
        bool isPrime = true; // Move initialization to here
        for (long j = 2; j < i; j++) // you actually only need to check up to sqrt(i)
        {
            if (i % j == 0) // you don't need the first condition
            {
                isPrime = false;
                break;
            }
        }
        if (isPrime)
        {
            Console.WriteLine ( "Prime:" + i );
        }
        // isPrime = true;
    }
}

You only need to check odd divisors up to the square root of the number.您只需要检查奇数除数直到数字的平方根。 In other words your inner loop needs to start:换句话说,您的内部循环需要启动:

for (int j = 3; j <= Math.Sqrt(i); j+=2) { ... }

You can also break out of the function as soon as you find the number is not prime, you don't need to check any more divisors (I see you're already doing that!).您也可以在发现数字不是质数时立即跳出该函数,您无需再检查除数(我知道您已经在这样做了!)。

This will only work if num is bigger than two.这仅在 num 大于 2 时才有效。

No Sqrt无平方

You can avoid the Sqrt altogether by keeping a running sum.您可以通过保持运行总和来完全避免 Sqrt。 For example:例如:

int square_sum=1;
for (int j=3; square_sum<i; square_sum+=4*(j++-1)) {...}

This is because the sum of numbers 1+(3+5)+(7+9) will give you a sequence of odd squares (1,9,25 etc).这是因为数字 1+(3+5)+(7+9) 的总和会给你一个奇数平方序列(1,9,25 等)。 And hence j represents the square root of square_sum .因此j代表square_sum As long as square_sum is less than i then j is less than the square root.只要square_sum小于ij小于平方根。

People have mentioned a couple of the building blocks toward doing this efficiently, but nobody's really put the pieces together.人们已经提到了有效地做到这一点的几个组成部分,但没有人真正将这些部分放在一起。 The sieve of Eratosthenes is a good start, but with it you'll run out of memory long before you reach the limit you've set. Eratosthenes筛子是一个好的开始,但是使用它你会在达到你设置的限制之前很久就耗尽内存。 That doesn't mean it's useless though -- when you're doing your loop, what you really care about are prime divisors.但这并不意味着它没用——当你在做你的循环时,你真正关心的是质数除数。 As such, you can start by using the sieve to create a base of prime divisors, then use those in the loop to test numbers for primacy.因此,您可以首先使用筛选器创建素数除数的基数,然后使用循环中的那些来测试数字的素数。

When you write the loop, however, you really do NOT want to us sqrt(i) in the loop condition as a couple of answers have suggested.然而,当你编写循环时,你真的不希望我们在循环条件中使用 sqrt(i) ,正如一些答案所建议的那样。 You and I know that the sqrt is a "pure" function that always gives the same answer if given the same input parameter.你我都知道 sqrt 是一个“纯”函数,如果给定相同的输入参数,它总是给出相同的答案。 Unfortunately, the compiler does NOT know that, so if use something like '<=Math.sqrt(x)' in the loop condition, it'll re-compute the sqrt of the number every iteration of the loop.不幸的是,编译器不知道这一点,所以如果在循环条件中使用类似 '<=Math.sqrt(x)' 的东西,它会在循环的每次迭代中重新计算数字的 sqrt。

You can avoid that a couple of different ways.您可以通过几种不同的方式来避免这种情况。 You can either pre-compute the sqrt before the loop, and use the pre-computed value in the loop condition, or you can work in the other direction, and change i<Math.sqrt(x) to i*i<x .您可以在循环之前预先计算 sqrt,并在循环条件中使用预先计算的值,或者您可以在另一个方向工作,并将i<Math.sqrt(x)更改为i*i<x Personally, I'd pre-compute the square root though -- I think it's clearer and probably a bit faster--but that depends on the number of iterations of the loop (the i*i means it's still doing a multiplication in the loop).就我个人而言,我会预先计算平方根——我认为它更清晰,可能更快——但这取决于循环的迭代次数( i*i意味着它仍在循环中进行乘法运算)。 With only a few iterations, i*i will typically be faster.只需几次迭代, i*i通常会更快。 With enough iterations, the loss from i*i every iteration outweighs the time for executing sqrt once outside the loop.通过足够的迭代,每次迭代i*i的损失超过在循环外执行sqrt一次的时间。

That's probably adequate for the size of numbers you're dealing with -- a 15 digit limit means the square root is 7 or 8 digits, which fits in a pretty reasonable amount of memory.这对于您正在处理的数字的大小来说可能已经足够了——15 位限制意味着平方根是 7 或 8 位,这适合相当合理的内存量。 On the other hand, if you want to deal with numbers in this range a lot, you might want to look at some of the more sophisticated prime-checking algorithms, such as Pollard's or Brent's algorithms .另一方面,如果您想大量处理这个范围内的数字,您可能需要查看一些更复杂的素数检查算法,例如Pollard 或 Brent 算法 These are more complex (to put it mildly) but a lot faster for large numbers.这些更复杂(委婉地说),但对于大数字来说快得多。

There are other algorithms for even bigger numbers ( quadratic sieve , general number field sieve ) but we won't get into them for the moment -- they're a lot more complex, and really only useful for dealing with really big numbers (the GNFS starts to be useful in the 100+ digit range).对于更大的数字,还有其他算法(二次筛一般数域筛),但我们暂时不会讨论它们——它们要复杂得多,而且实际上只对处理非常大的数字有用( GNFS 开始在 100+ 位范围内有用)。

First step: write an extension method to find out if an input is prime第一步:写一个扩展方法来判断一个输入是否是素数

public static bool isPrime(this int number ) {

    for (int i = 2; i < number; i++) { 
        if (number % i == 0) { 
            return false; 
        } 
    }

    return true;   
}

2 step: write the method that will print all prime numbers that are between 0 and the number input第 2 步:编写打印所有介于 0 和输入数字之间的素数的方法

public static void getAllPrimes(int number)
{
    for (int i = 0; i < number; i++)
    {
        if (i.isPrime()) Console.WriteLine(i);
    }
}

EDIT_ADD: If Will Ness is correct that the question's purpose is just to output a continuous stream of primes for as long as the program is run (pressing Pause/Break to pause and any key to start again) with no serious hope of every getting to that upper limit, then the code should be written with no upper limit argument and a range check of "true" for the first 'i' for loop. EDIT_ADD:如果 Will Ness 是正确的,那么这个问题的目的只是在程序运行期间输出连续的素数流(按暂停/中断暂停,按任意键重新开始),没有认真的希望那个上限,那么代码应该写成没有上限参数和第一个“i”循环的“真”范围检查。 On the other hand, if the question wanted to actually print the primes up to a limit, then the following code will do the job much more efficiently using Trial Division only for odd numbers, with the advantage that it doesn't use memory at all (it could also be converted to a continuous loop as per the above):另一方面,如果问题想要实际打印质数达到极限,那么以下代码将仅对奇数使用 Trial Division 更有效地完成这项工作,其优点是它根本不使用内存(它也可以转换为如上所述的连续循环):

static void primesttt(ulong top_number) {
  Console.WriteLine("Prime:  2");
  for (var i = 3UL; i <= top_number; i += 2) {
    var isPrime = true;
    for (uint j = 3u, lim = (uint)Math.Sqrt((double)i); j <= lim; j += 2) {
      if (i % j == 0)  {
        isPrime = false;
        break;
      }
    }
    if (isPrime) Console.WriteLine("Prime:  {0} ", i);
  }
}

First, the question code produces no output because of that its loop variables are integers and the limit tested is a huge long integer, meaning that it is impossible for the loop to reach the limit producing an inner loop EDITED: whereby the variable 'j' loops back around to negative numbers;首先,问题代码不产生任何输出,因为它的循环变量是整数,并且测试的限制是一个巨大的长整数,这意味着循环不可能达到产生内循环的限制编辑:变量'j'循环回到负数; when the 'j' variable comes back around to -1, the tested number fails the prime test because all numbers are evenly divisible by -1 END_EDIT .当 'j' 变量回到 -1 时,被测试的数字无法通过质数测试,因为所有数字都可以被 -1 END_EDIT整除。 Even if this were corrected, the question code produces very slow output because it gets bound up doing 64-bit divisions of very large quantities of composite numbers (all the even numbers plus the odd composites) by the whole range of numbers up to that top number of ten raised to the sixteenth power for each prime that it can possibly produce.即使这一点得到纠正,问题代码也会产生非常慢的输出,因为它会被限制在对非常大量的复合数(所有偶数加上奇数复合数)进行 64 位除法,直到那个顶部的整个数字范围对于它可能产生的每个素数,10 的 16 次方数。 The above code works because it limits the computation to only the odd numbers and only does modulo divisions up to the square root of the current number being tested .上面的代码之所以有效,是因为它将计算限制为仅奇数,并且仅对当前被测试数的平方根进行模除。

This takes an hour or so to display the primes up to a billion, so one can imagine the amount of time it would take to show all the primes to ten thousand trillion (10 raised to the sixteenth power), especially as the calculation gets slower with increasing range.这需要一个小时左右才能显示 10 亿以内的质数,因此可以想象将所有质数显示为 10000 万亿(10 的 16 次方)所需的时间,尤其是当计算变慢时随着范围的增加。 END_EDIT_ADD END_EDIT_ADD

Although the one liner (kind of) answer by @SLaks using Linq works, it isn't really the Sieve of Eratosthenes as it is just an unoptimised version of Trial Division , unoptimised in that it does not eliminate odd primes, doesn't start at the square of the found base prime, and doesn't stop culling for base primes larger than the square root of the top number to sieve.尽管@SLaks 使用 Linq 给出的一个(某种)答案有效,但它并不是真正的 Eratosthenes 筛法,因为它只是Trial Division的未优化版本,未优化的原因在于它没有消除奇数素数,没有开始在找到的基本素数的平方处,并且不会停止剔除大于要筛选的顶部数字的平方根的基本素数。 It is also quite slow due to the multiple nested enumeration operations.由于多个嵌套的枚举操作,它也很慢。

It is actually an abuse of the Linq Aggregate method and doesn't effectively use the first of the two Linq Range's generated.它实际上是对 Linq Aggregate 方法的滥用,并没有有效地使用生成的两个 Linq Range 中的第一个。 It can become an optimized Trial Division with less enumeration overhead as follows:它可以成为一个优化的 Trial Division,具有更少的枚举开销,如下所示:

static IEnumerable<int> primes(uint top_number) {
  var cullbf = Enumerable.Range(2, (int)top_number).ToList();
  for (int i = 0; i < cullbf.Count; i++) {
    var bp = cullbf[i]; var sqr = bp * bp; if (sqr > top_number) break;
    cullbf.RemoveAll(c => c >= sqr && c % bp == 0);
  } return cullbf; }

which runs many times faster than the SLaks answer.它的运行速度比 SLaks 答案快很多倍。 However, it is still slow and memory intensive due to the List generation and the multiple enumerations as well as the multiple divide (implied by the modulo) operations.但是,由于 List 生成和多个枚举以及多个除法(由模暗示)操作,它仍然很慢并且占用大量内存。

The following true Sieve of Eratosthenes implementation runs about 30 times faster and takes much less memory as it only uses a one bit representation per number sieved and limits its enumeration to the final iterator sequence output, as well having the optimisations of only treating odd composites, and only culling from the squares of the base primes for base primes up to the square root of the maximum number, as follows:以下真正的 Eratosthenes 实现运行速度快了大约 30 倍,并且占用的内存更少,因为它对每个筛选的数字仅使用一位表示并将其枚举限制为最终的迭代器序列输出,以及仅处理奇数复合的优化,并且只从基素数的平方中剔除基素数直到最大数的平方根,如下所示:

static IEnumerable<uint> primes(uint top_number) {
  if (top_number < 2u) yield break;
  yield return 2u; if (top_number < 3u) yield break;
  var BFLMT = (top_number - 3u) / 2u;
  var SQRTLMT = ((uint)(Math.Sqrt((double)top_number)) - 3u) / 2u;
  var buf = new BitArray((int)BFLMT + 1,true);
  for (var i = 0u; i <= BFLMT; ++i) if (buf[(int)i]) {
      var p = 3u + i + i; if (i <= SQRTLMT) {
        for (var j = (p * p - 3u) / 2u; j <= BFLMT; j += p)
          buf[(int)j] = false; } yield return p; } }

The above code calculates all the primes to ten million range in about 77 milliseconds on an Intel i7-2700K (3.5 GHz).上面的代码在英特尔 i7-2700K (3.5 GHz) 上计算了大约 77 毫秒内到一千万范围的所有质数。

Either of the two static methods can be called and tested with the using statements and with the static Main method as follows:可以使用 using 语句和静态 Main 方法调用和测试这两个静态方法中的任何一个,如下所示:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

static void Main(string[] args) {
  Console.WriteLine("This program generates prime sequences.\r\n");

  var n = 10000000u;

  var elpsd = -DateTime.Now.Ticks;

  var count = 0; var lastp = 0u;
  foreach (var p in primes(n)) { if (p > n) break; ++count; lastp = (uint)p; }

  elpsd += DateTime.Now.Ticks;
  Console.WriteLine(
    "{0} primes found <= {1}; the last one is {2} in {3} milliseconds.",
    count, n, lastp,elpsd / 10000);

  Console.Write("\r\nPress any key to exit:");
  Console.ReadKey(true);
  Console.WriteLine();
}

which will show the number of primes in the sequence up to the limit, the last prime found, and the time expended in enumerating that far.它将显示序列中达到极限的素数数量,找到的最后一个素数,以及枚举该距离所花费的时间。

EDIT_ADD: However, in order to produce an enumeration of the number of primes less than ten thousand trillion (ten to the sixteenth power) as the question asks, a segmented paged approach using multi-core processing is required but even with C++ and the very highly optimized PrimeSieve , this would require something over 400 hours to just produce the number of primes found, and tens of times that long to enumerate all of them so over a year to do what the question asks. EDIT_ADD:但是,为了产生问题所要求的小于一万万亿(十到十六次方)的素数数量的枚举,需要使用多核处理的分段分页方法,但即使使用 C++ 和非常高度优化的 PrimeSieve ,这将需要超过 400 个小时才能产生找到的素数数量,并且需要数十倍的时间来枚举所有这些素数,因此一年多来做问题所要求的。 To do it using the un-optimized Trial Division algorithm attempted, it will take super eons and a very very long time even using an optimized Trial Division algorithm as in something like ten to the two millionth power years (that's two million zeros years!!!).要使用未优化的 Trial Division 算法来做到这一点,即使使用优化的 Trial Division 算法也需要花费超长的时间和非常长的时间,例如 10 到 200 万次幂年(即 200 万个零年!! !)。

It isn't much wonder that his desktop machine just sat and stalled when he tried it!!!!难怪他的台式机在他尝试的时候就停滞不前了!!!! If he had tried a smaller range such as one million, he still would have found it takes in the range of seconds as implemented.如果他尝试了一个更小的范围,比如一百万,他仍然会发现它在实施时需要几秒钟的时间。

The solutions I post here won't cut it either as even the last Sieve of Eratosthenes one will require about 640 Terabytes of memory for that range.我在这里发布的解决方案也不会削减它,因为即使是最后一个 Eratosthenes 筛网,该范围也需要大约 640 TB 的内存。

That is why only a page segmented approach such as that of PrimeSieve can handle this sort of problem for the range as specified at all, and even that requires a very long time, as in weeks to years unless one has access to a super computer with hundreds of thousands of cores.这就是为什么只有像 PrimeSieve 这样的页面分段方法才能完全处理指定范围内的此类问题,即使这样也需要很长的时间,如数周到数年,除非人们可以访问具有以下功能的超级计算机数十万个内核。 END_EDIT_ADD END_EDIT_ADD

It may just be my opinion, but there's another serious error in your program (setting aside the given 'prime number' question, which has been thoroughly answered).这可能只是我的意见,但您的程序中存在另一个严重错误(搁置已彻底回答的给定“质数”问题)。

Like the rest of the responders, I'm assuming this is homework, which indicates you want to become a developer (presumably).像其他响应者一样,我假设这是家庭作业,这表明您想成为一名开发人员(大概)。

You need to learn to compartmentalize your code.你需要学会划分你的代码。 It's not something you'll always need to do in a project, but it's good to know how to do it.这不是你在项目中总是需要做的事情,但知道如何去做是件好事。

Your method prime_num(long num) could stand a better, more descriptive name.您的方法 prime_num(long num) 可以采用更好、更具描述性的名称。 And if it is supposed to find all prime numbers less than a given number, it should return them as a list.如果它应该找到小于给定数字的所有素数,它应该将它们作为列表返回。 This makes it easier to seperate your display and your functionality.这样可以更轻松地分离您的显示器和您的功能。

If it simply returned an IList containing prime numbers you could then display them in your main function (perhaps calling another outside function to pretty print them) or use them in further calculations down the line.如果它只是返回一个包含素数的 IList,那么你可以在你的主函数中显示它们(也许调用另一个外部函数来漂亮地打印它们)或者在后续的进一步计算中使用它们。

So my best recommendation to you is to do something like this:所以我对你最好的建议是做这样的事情:

public void main(string args[])
{
    //Get the number you want to use as input
    long x = number;//'number' can be hard coded or retrieved from ReadLine() or from the given arguments

    IList<long> primes = FindSmallerPrimes(number);

    DisplayPrimes(primes);
}

public IList<long> FindSmallerPrimes(long largestNumber)
{
    List<long> returnList = new List<long>();
    //Find the primes, using a method as described by another answer, add them to returnList
    return returnList;
}

public void DisplayPrimes(IList<long> primes)
{
    foreach(long l in primes)
    {
        Console.WriteLine ( "Prime:" + l.ToString() );
    }
}

Even if you end up working somewhere where speration like this isn't needed, it's good to know how to do it.即使你最终在不需要这样的分散的地方工作,知道如何去做也是很好的。

Smells like more homework.闻起来像更多的家庭作业。 My very very old graphing calculator had a is prime program like this.我非常非常古老的图形计算器有一个像这样的主要程序。 Technnically the inner devision checking loop only needs to run to i^(1/2).从技术上讲,内部设备检查循环只需要运行到 i^(1/2)。 Do you need to find "all" prime numbers between 0 and L ?您是否需要在 0 和 L 之间找到“所有”质数? The other major problem is that your loop variables are "int" while your input data is "long", this will be causing an overflow making your loops fail to execute even once.另一个主要问题是您的循环变量是“int”,而您的输入数据是“long”,这将导致溢出,使您的循环甚至无法执行一次。 Fix the loop variables.修复循环变量。

One line code in C# :- C# 中的一行代码:-

Console.WriteLine(String.Join(Environment.NewLine, 
    Enumerable.Range(2, 300)
        .Where(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1)
        .All(nn => n % nn != 0)).ToArray()));                                    

The Sieve of Eratosthenes answer above is not quite correct.上面的 Eratosthenes答案的筛子并不完全正确。 As written it will find all the primes between 1 and 1000000. To find all the primes between 1 and num use:正如所写,它将查找 1 到 1000000 之间的所有素数。要查找 1 和 num 之间的所有素数,请使用:

private static IEnumerable Primes01(int num)
{
    return Enumerable.Range(1, Convert.ToInt32(Math.Floor(Math.Sqrt(num))))
        .Aggregate(Enumerable.Range(1, num).ToList(),
        (result, index) =>
            {
                result.RemoveAll(i => i > result[index] && i%result[index] == 0);
                return result;
            }
        );
}

The seed of the Aggregate should be range 1 to num since this list will contain the final list of primes. Aggregate 的种子应该在 1 到 num 的范围内,因为这个列表将包含最终的素数列表。 The Enumerable.Range(1, Convert.ToInt32(Math.Floor(Math.Sqrt(num)))) is the number of times the seed is purged. Enumerable.Range(1, Convert.ToInt32(Math.Floor(Math.Sqrt(num))))是种子被清除的次数。

so this is basically just two typos , one, the most unfortunate, for (int j = 2; j <= num; j++) which is the reason for the unproductive testing of 1%2,1%3 ... 1%(10^15-1) which goes on for very long time so the OP didn't get "any output" .所以这基本上只是两个错别字,一个是最不幸的, for (int j = 2; j <= num; j++)这就是1%2,1%3 ... 1%(10^15-1)持续了很长时间,所以 OP 没有得到“任何输出” It should've been j < i;应该是j < i; instead.反而。 The other, minor one in comparison, is that i should start from 2, not from 0:另一个比较次要的是, i应该从 2 开始,而不是从 0 开始:

for( i=2; i <= num; i++ )
{
    for( j=2; j < i; j++ ) // j <= sqrt(i) is really enough
....

Surely it can't be reasonably expected of a console print-out of 28 trillion primes or so to be completed in any reasonable time-frame.当然,不能合理地期望在任何合理的时间范围内完成 28 万亿个左右的控制台打印输出 So, the original intent of the problem was obviously to print out a steady stream of primes, indefinitely .所以,这个问题的初衷显然是无限期地打印出源源不断的质数。 Hence all the solutions proposing simple use of sieve of Eratosthenes are totally without merit here, because simple sieve of Eratosthenes is bounded - a limit must be set in advance.因此,所有建议使用简单埃拉托色尼筛的解决方案是完全没有道理在这里,因为埃拉托色尼的简单筛是有界的-限制必须提前设定。

What could work here is the optimized trial division which would save the primes as it finds them, and test against the primes, not just all numbers below the candidate.在这里可以工作的是优化的试验除法,它会在找到素数时保存它们,并针对素数进行测试,而不仅仅是候选者下方的所有数字。

Second alternative, with much better complexity (ie much faster) is to use a segmented sieve of Eratosthenes .第二种选择,具有更好的复杂性(即更快)是使用Eratosthenes分段筛 Which is incremental and unbounded.这是增量和无限的。

Both these schemes would use double-staged production of primes : one would produce and save the primes, to be used by the other stage in testing (or sieving), much above the limit of the first stage (below its square of course - automatically extending the first stage, as the second stage would go further and further up).这两种方案都将使用双阶段生产素数:一个将生成并保存素数,以供另一阶段用于测试(或筛分),远高于第一阶段的限制(当然低于其平方 - 自动延长第一阶段,因为第二阶段会越来越远)。

ExchangeCore Forums have a good console application listed that looks to write found primes to a file, it looks like you can also use that same file as a starting point so you don't have to restart finding primes from 2 and they provide a download of that file with all found primes up to 100 million so it would be a good start. ExchangeCore 论坛列出了一个很好的控制台应用程序,可以将找到的素数写入文件,看起来您也可以使用相同的文件作为起点,因此您不必重新从 2 开始查找素数,并且它们提供了该文件包含所有已找到的质数,最多 1 亿个,因此这将是一个好的开始。

The algorithm on the page also takes a couple shortcuts (odd numbers and only checks up to the square root) which makes it extremely efficient and it will allow you to calculate long numbers.页面上的算法还采用了一些快捷方式(奇数,只检查平方根),这使得它非常有效,并且可以让您计算长数。

To be quite frank, some of the suggested solutions are really slow, and therefore are bad suggestions.坦率地说,一些建议的解决方案真的很慢,因此是不好的建议。 For testing a single number to be prime you need some dividing/modulo operator, but for calculating a range you don't have to.为了测试单个数字为素数,您需要一些除法/模运算符,但为了计算范围,您不必这样做。

Basically you just exclude numbers that are multiples of earlier found primes, as the are (by definition) not primes themselves.基本上,您只需排除是较早发现的素数倍数的数字,因为它们(根据定义)不是素数本身。

I will not give the full implementation, as that would be to easy, this is the approach in pseudo code.我不会给出完整的实现,因为这很容易,这是伪代码中的方法。 (On my machine, the actual implementation calculates all primes in an Sytem.Int32 (2 bilion) within 8 seconds. (在我的机器上,实际实现会在 8 秒内计算 Sytem.Int32(2 亿)中的所有素数。

public IEnumerable<long> GetPrimes(long max)
{
    // we safe the result set in an array of bytes.
    var buffer = new byte[long >> 4];
    // 1 is not a prime.
    buffer[0] = 1;

    var iMax = (long)Math.Sqrt(max);

    for(long i = 3; i <= iMax; i +=2 )
    {
        // find the index in the buffer
        var index = i >> 4;
        // find the bit of the buffer.
        var bit = (i >> 1) & 7;

        // A not set bit means: prime
        if((buffer[index] & (1 << bit)) == 0)
        {
            var step = i << 2;
            while(step < max)
            {
                // find position in the buffer to write bits that represent number that are not prime.
            }
        }
        // 2 is not in the buffer.
        yield return 2;

        // loop through buffer and yield return odd primes too.
    }
}

The solution requires a good understanding of bitwise operations.该解决方案需要对按位运算有很好的理解。 But it ways, and ways faster.但它的方式,而且方式更快。 You also can safe the result of the outcome on disc, if you need them for later use.如果您需要它们以备后用,您还可以将结果保存在光盘上。 The result of 17 * 10^9 numbers can be safed with 1 GB, and the calculation of that result set takes about 2 minutes max. 17 * 10^9 数字的结果可以用 1 GB 来保护,并且该结果集的计算最多需要大约 2 分钟。

I know this is quiet old question, but after reading here: Sieve of Eratosthenes Wiki我知道这是一个安静的老问题,但在这里阅读后: Eratosthenes Wiki 的筛选

This is the way i wrote it from understanding the algorithm:这是我通过理解算法编写它的方式:

void SieveOfEratosthenes(int n)
{
    bool[] primes = new bool[n + 1];

    for (int i = 0; i < n; i++)
        primes[i] = true;

    for (int i = 2; i * i <= n; i++)
        if (primes[i])
            for (int j = i * 2; j <= n; j += i)
                primes[j] = false;

    for (int i = 2; i <= n; i++)
        if (primes[i]) Console.Write(i + " ");
}

In the first loop we fill the array of booleans with true.在第一个循环中,我们用 true 填充布尔数组。

Second for loop will start from 2 since 1 is not a prime number and will check if prime number is still not changed and then assign false to the index of j.第二个 for 循环将从 2 开始,因为 1 不是素数,并且将检查素数是否仍然没有改变,然后将 false 分配给 j 的索引。

last loop we just printing when it is prime.最后一个循环我们只是在它是素数时打印。

Very similar - from an exercise to implement Sieve of Eratosthenes in C#:非常相似 - 来自在 C# 中实现 Eratosthenes 筛分的练习:

public class PrimeFinder
{
    readonly List<long> _primes = new List<long>();

    public PrimeFinder(long seed)
    {
        CalcPrimes(seed);
    }

    public List<long> Primes { get { return _primes; } }

    private void CalcPrimes(long maxValue)
    {
        for (int checkValue = 3; checkValue <= maxValue; checkValue += 2)
        {
            if (IsPrime(checkValue))
            {
                _primes.Add(checkValue);
            }
        }
    }

    private bool IsPrime(long checkValue)
    {
        bool isPrime = true;

        foreach (long prime in _primes)
        {
            if ((checkValue % prime) == 0 && prime <= Math.Sqrt(checkValue))
            {
                isPrime = false;
                break;
            }
        }
        return isPrime;
    }
}

U can use the normal prime number concept must only two factors (one and itself). U 可以使用正常的质数概念必须只有两个因数(一个和它本身)。 So do like this,easy way所以这样做,简单的方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PrimeNUmber
{
    class Program
    {
        static void FindPrimeNumber(long num)
        {
            for (long i = 1; i <= num; i++)
            {
                int totalFactors = 0;
                for (int j = 1; j <= i; j++)
                {
                    if (i % j == 0)
                    {
                        totalFactors = totalFactors + 1;
                    }
                }
                if (totalFactors == 2)
                {
                    Console.WriteLine(i);
                }
            }
        }

        static void Main(string[] args)
        {
            long num;
            Console.WriteLine("Enter any value");
            num = Convert.ToInt64(Console.ReadLine());
            FindPrimeNumber(num);
            Console.ReadLine();
        }
    }
}

This is the fastest way to calculate prime numbers in C#.这是在 C# 中计算素数的最快方法。

   void PrimeNumber(long number)
    {
        bool IsprimeNumber = true;
        long  value = Convert.ToInt32(Math.Sqrt(number));
        if (number % 2 == 0)
        {
            IsprimeNumber = false;
        }
        for (long i = 3; i <= value; i=i+2)
        {             
           if (number % i == 0)
            {

               // MessageBox.Show("It is divisible by" + i);
                IsprimeNumber = false;
                break;
            }

        }
        if (IsprimeNumber)
        {
            MessageBox.Show("Yes Prime Number");
        }
        else
        {
            MessageBox.Show("No It is not a Prime NUmber");
        }
    }

This solution displays all prime numbers between 0 and 100.此解决方案显示 0 到 100 之间的所有素数。

        int counter = 0;
        for (int c = 0; c <= 100; c++)
        {
            counter = 0;
            for (int i = 1; i <= c; i++)
            {
                if (c % i == 0)
                { counter++; }
            }
            if (counter == 2)
            { Console.Write(c + " "); }
        }
class CheckIfPrime
   {
    static void Main()
      {
          while (true)
        {
            Console.Write("Enter a number: ");
            decimal a = decimal.Parse(Console.ReadLine());
            decimal[] k = new decimal[int.Parse(a.ToString())];
            decimal p = 0;
            for (int i = 2; i < a; i++)
            {
                if (a % i != 0)
                {
                    p += i;
                    k[i] = i;
                }
                else
                    p += i;
            }
            if (p == k.Sum())
               { Console.WriteLine ("{0} is prime!", a);}
            else
               {Console.WriteLine("{0} is NOT prime", a);}

        }
    }

}

There are some very optimal ways to implement the algorithm.有一些非常优化的方法来实现该算法。 But if you don't know much about maths and you simply follow the definition of prime as the requirement: a number that is only divisible by 1 and by itself (and nothing else), here's a simple to understand code for positive numbers.但是,如果您对数学不太了解,并且您只是遵循素数的定义作为要求:一个只能被 1 和它自己整除(不能被其他任何东西)整除的数字,那么这里有一个简单易懂的正数代码。

public bool IsPrime(int candidateNumber)
{
    int fromNumber = 2;
    int toNumber = candidateNumber - 1;

    while(fromNumber <= toNumber)
    {
        bool isDivisible = candidateNumber % fromNumber == 0;
        if (isDivisible)
        {
            return false;
        }

        fromNumber++;
    }
    return true;
}

Since every number is divisible by 1 and by itself, we start checking from 2 onwards until the number immediately before itself.因为每个数字都可以被 1 和它自己整除,所以我们从 2 开始检查,直到它之前的数字。 That's the basic reasoning.这就是基本的推理。

You can do also this:你也可以这样做:

class Program
  {
    static void Main(string[] args)
    {
      long numberToTest = 350124;
      bool isPrime = NumberIsPrime(numberToTest);
      Console.WriteLine(string.Format("Number {0} is prime? {1}", numberToTest, isPrime));
      Console.ReadLine();
    }

    private static bool NumberIsPrime(long n)
    {
      bool retVal = true;

      if (n <= 3)
      {
        retVal = n > 1;
      } else if (n % 2 == 0 || n % 3 == 0)
      {
        retVal = false;
      }

      int i = 5;

      while (i * i <= n)
      {
        if (n % i == 0 || n % (i + 2) == 0)
        {
          retVal = false;
        }
        i += 6;
      }

      return retVal;
    }
  }

An easier approach , what i did is check if a number have exactly two division factors which is the essence of prime numbers .一种更简单的方法,我所做的是检查一个数字是否恰好有两个除法因子,这正是素数的本质。

    List<int> factorList = new List<int>();
    int[] numArray = new int[] { 1, 0, 6, 9, 7, 5, 3, 6, 0, 8, 1 };

    foreach (int item in numArray)
    {

        for (int x = 1; x <= item; x++)
        {
          //check for the remainder after dividing for each number less that number
            if (item % x == 0)
            {
                factorList.Add(x);
            }
        }
        if (factorList.Count == 2) // has only 2 division factors ; prime number
        {
            Console.WriteLine(item + " is a prime number ");
        }
        else
        {Console.WriteLine(item + " is not a prime number ");}

        factorList = new List<int>(); // reinitialize list
    }

Here is a solution with unit test:这是带有单元测试的解决方案:

The solution:解决方案:

public class PrimeNumbersKata
    {
        public int CountPrimeNumbers(int n)
        {
            if (n < 0) throw new ArgumentException("Not valide numbre");
            if (n == 0 || n == 1) return 0;
            int cpt = 0;
            for (int i = 2; i <= n; i++)
            {
                if (IsPrimaire(i)) cpt++;
            }
            return cpt;
        }

        private bool IsPrimaire(int number)
        {

            for (int i = 2; i <= number / 2; i++)
            {
                if (number % i == 0) return false;
            }
            return true;
        }
    }

The tests:测试:

[TestFixture]
    class PrimeNumbersKataTest
    {
        private PrimeNumbersKata primeNumbersKata;
        [SetUp]
        public void Init()
        {
            primeNumbersKata = new PrimeNumbersKata();
        }
        [TestCase(1,0)]
        [TestCase(0,0)]
        [TestCase(2,1)]
        [TestCase(3,2)]
        [TestCase(5,3)]
        [TestCase(7,4)]
        [TestCase(9,4)]
        [TestCase(11,5)]
        [TestCase(13,6)]
        public void CountPrimeNumbers_N_AsArgument_returnCountPrimes(int n, int expected)
        {
            //arrange
            //act
            var actual = primeNumbersKata.CountPrimeNumbers(n);
            //assert
            Assert.AreEqual(expected,actual);
        }

        [Test]
        public void CountPrimairs_N_IsNegative_RaiseAnException()
        {
            var ex = Assert.Throws<ArgumentException>(()=> { primeNumbersKata.CountPrimeNumbers(-1); });
            //Assert.That(ex.Message == "Not valide numbre");
             Assert.That(ex.Message, Is.EqualTo("Not valide numbre"));

        }
    }

in the university it was necessary to count prime numbers up to 10,000 did so, the teacher was a little surprised, but I passed the test.在大学里要数到10000的质数才这样做,老师有点惊讶,但我通过了考试。 Lang c#朗c#

void Main()
{
    int number=1;
    for(long i=2;i<10000;i++)
    {
        if(PrimeTest(i))
        {
            Console.WriteLine(number+++" " +i);
        }
    }
}

List<long> KnownPrime = new List<long>();
private bool PrimeTest(long i)
{
    if (i == 1) return false;
    if (i == 2)
    {
        KnownPrime.Add(i);
        return true;
    }
    foreach(int k in KnownPrime)
    {
        if(i%k==0)
            return false;
    }
    KnownPrime.Add(i);
    return true;
}

for (int i = 2; i < 100; i++) { bool isPrimeNumber = true; for (int i = 2; i < 100; i++) { bool isPrimeNumber = true; for (int j = 2; j <= i && j <= 100; j++) { if (i != j && i % j == 0) { isPrimeNumber = false; for (int j = 2; j <= i && j <= 100; j++) { if (i != j && i % j == 0) { isPrimeNumber = false; break;休息; } } if (isPrimeNumber) { Console.WriteLine(i); } } if (isPrimeNumber) { Console.WriteLine(i); } } } }

Prime Helper very fast calculation Prime Helper 计算速度非常快

public static class PrimeHelper
{

    public static IEnumerable<Int32> FindPrimes(Int32 maxNumber)
    {
        return (new PrimesInt32(maxNumber));
    }

    public static IEnumerable<Int32> FindPrimes(Int32 minNumber, Int32 maxNumber)
    {
        return FindPrimes(maxNumber).Where(pn => pn >= minNumber);
    }

    public static bool IsPrime(this Int64 number)
    {
        if (number < 2)
            return false;
        else if (number < 4 )
            return true;

        var limit = (Int32)System.Math.Sqrt(number) + 1;
        var foundPrimes = new PrimesInt32(limit);

        return !foundPrimes.IsDivisible(number);
    }

    public static bool IsPrime(this Int32 number)
    {
        return IsPrime(Convert.ToInt64(number));
    }

    public static bool IsPrime(this Int16 number)
    {
        return IsPrime(Convert.ToInt64(number));
    }

    public static bool IsPrime(this byte number)
    {
        return IsPrime(Convert.ToInt64(number));
    }
}

public class PrimesInt32 : IEnumerable<Int32>
{
    private Int32 limit;
    private BitArray numbers;

    public PrimesInt32(Int32 limit)
    {
        if (limit < 2)
            throw new Exception("Prime numbers not found.");

        startTime = DateTime.Now;
        calculateTime = startTime - startTime;
        this.limit = limit;
        try { findPrimes(); } catch{/*Overflows or Out of Memory*/}

        calculateTime = DateTime.Now - startTime;
    }

    private void findPrimes()
    {
        /*
        The Sieve Algorithm
        http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
        */
        numbers = new BitArray(limit, true);
        for (Int32 i = 2; i < limit; i++)
            if (numbers[i])
                for (Int32 j = i * 2; j < limit; j += i)
                     numbers[j] = false;
    }

    public IEnumerator<Int32> GetEnumerator()
    {
        for (Int32 i = 2; i < 3; i++)
            if (numbers[i])
                yield return i;
        if (limit > 2)
            for (Int32 i = 3; i < limit; i += 2)
                if (numbers[i])
                    yield return i;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    // Extended for Int64
    public bool IsDivisible(Int64 number)
    {
        var sqrt = System.Math.Sqrt(number);
        foreach (var prime in this)
        {
            if (prime > sqrt)
                break;
            if (number % prime == 0)
            {
                DivisibleBy = prime;
                return true;
            }
        }
        return false;
    }

    private static DateTime startTime;
    private static TimeSpan calculateTime;
    public static TimeSpan CalculateTime { get { return calculateTime; } }
    public Int32 DivisibleBy { get; set; }
}
    public static void Main()
    {  
        Console.WriteLine("enter the number");
        int i = int.Parse(Console.ReadLine());

        for (int j = 2; j <= i; j++)
        {
            for (int k = 2; k <= i; k++)
            {
                if (j == k)
                {
                    Console.WriteLine("{0}is prime", j);

                    break;
                }
                else if (j % k == 0)
                {
                    break;
                }
            }
        }
        Console.ReadLine();          
    }
static void Main(string[] args)
    {  int i,j;
        Console.WriteLine("prime no between 1 to 100");
    for (i = 2; i <= 100; i++)
    {
        int count = 0;
        for (j = 1; j <= i; j++)
        {

            if (i % j == 0)
            { count=count+1; }
        }

        if ( count <= 2)
        { Console.WriteLine(i); }


    }
    Console.ReadKey();

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM