优化素数生成代码?

时间:2013-08-05 23:43:00

标签: c# optimization primes

我编写了以下代码来计算和输出素数。

我得到的素数在控制台上输出,并存储在文本文件中。

计算所有数字直到指定的数字。

有关使此代码运行更快的任何建议更有效率?

    static void Main(string[] args)
    {
        long i;
        long j;    

           for (i = 3; i < 10000000; i += 2)
           {
               bool isPrime = true;

               for (j = 2; j <= i / 2; j++)
               {
                   if (i % j == 0)
                   {
                       isPrime = false;
                       break;
                   }
               }

               if (isPrime)
               {
                   Console.WriteLine(i);

                   using (System.IO.StreamWriter StreamWriter = System.IO.File.AppendText(@"C:\Users\Marco\Documents\Visual Studio 2012\Projects\Prime Number Generator\Prime Number Generator\bin\Debug\Prime List.txt"))
                   {
                       StreamWriter.WriteLine(i);
                   }
               }
           }
    }

由于

3 个答案:

答案 0 :(得分:1)

  1. 您需要在sqrt(i)之前检查除法,而不是i/2。 (正如@ I4V在下面的评论中正确指出的那样,j*j < i将比j < sqrt(i)更快,因为平方根是一个非常慢的操作cmp。到乘法)

  2. 您可以在循环中使用以前找到的素数(即将它们存储在数组中并循环遍历它们),因为您只需要通过素数检查可分性。

  3. 只有在优化算法之后,才能开始优化代码。

答案 1 :(得分:1)

您使用的算法称为试验分区,如果您在@sashkello和@giuliofranco建议的平方根处停留,则它具有时间复杂度O(n ^ 2)或O(n ^ 1.5)。一种更好的算法是两千多年前发明的Eratosthenes筛,其时间复杂度为O(n log log n),几乎为O(n)。 Eratosthenes的Sieve首先列出从2到最大期望素数 n 的所有数字,然后进入迭代阶段。在每一步中,识别出尚未考虑的最小的未交叉数,并且该数的所有倍数都被划掉;重复这一过程直到没有未交叉的数字仍未被考虑。所有未交叉的数字都是素数。

function primes(n)
    sieve := makeArray(2..n, True)
    for p from 2 to n step 1
        if sieve[p]
            output p
            for i from p*p to n step p
                sieve[i] := False

primes函数中,sieve是数字列表,当sieve[p]True时,未交叉的数字按升序排列,并作为素数输出被考虑,并且“交叉”的倍数由 i 上的循环完成;循环从p*p开始,因为所有较小的倍数已被较小的素数划掉。

如果你对使用素数进行编程感兴趣,我谦虚地在我的博客上推荐这个essay,它讨论了这个算法,给出了一个优化,它的速度加倍,在质数上提供了许多其他算法,以及提供五种语言的实现。

答案 2 :(得分:0)

1)以sqrt(i)结束你的循环,而不是(i / 2)。保存的时间值得您计算平方根所需的时间。

2)不要忘记你生成的数字。将它们保存到一个数组中(至少是最后一个数组),然后尝试将候选项除以您知道的最佳数字。如果x%y == 0,则y是素数,或者存在素数P

static void Main(string[] args)
{
    long i;
    int j;
    List<long> primes = new List<long>();
    primes.Add(2);
    long maxJ;

    using (System.IO.StreamWriter StreamWriter = System.IO.File.AppendText(@"C:\Users\Marco\Documents\Visual Studio 2012\Projects\Prime Number Generator\Prime Number Generator\bin\Debug\Prime List.txt"))
    {
        for (i = 3; i < 10000000; i += 2)
        {
            //Compute only once, rather that at each iteration
            maxJ = (long)Math.Sqrt(i);
            for (j = 0; j < primes.Count && primes[j] <= maxJ; ++j)
            {
                if (i % primes[j] == 0)
                {
                    goto EndOfOuterLoop;
                }
            }

            Console.WriteLine(i);
            StreamWriter.WriteLine(i);
            primes.Add(i);

            EndOfOuterLoop:
        }
    }
}

3)如果你真的想要达到最大可达到的速度,你应该使用AKSMiller-Rabin算法,这些算法可以检查数字在多项式时间内是否为素数(AKS总是正确的,米勒 - 拉宾有时可以说非素数是素数。