【问题标题】:Faster Prime Generation C#更快的 Prime 生成 C#
【发布时间】:2015-02-25 09:55:53
【问题描述】:

我知道关于同一个主题的 SO 已经有很多问题,但这个问题可能会有所不同。我研究了一些用于计算从 2 到 N 的素数的算法。我编写了以下算法来计算某个范围内的素数,例如从 NM 其中 M 可以与 10^10 一样大,并且 N 和M 可以是10^6

for (k = 0; k < t; k++)
{
    int[] indexOfPrimes = new int[m[k] - n[k] + 1];

    int index_1=2;
    int index_2=0;
    int counter = 0;

    for (index_1 = 2; index_1 < Math.Sqrt(m[k]);  index_1++)
    {
        counter = 0;
        for (index_2 = index_1*index_1; index_2 <= m[k];)
        {
            if (index_2 >= n[k] && index_2 <= m[k])
                indexOfPrimes[index_2 % (m[k] - n[k] + 1)] = 1;
            index_2 = (index_1 * index_1) + (index_1 * ++counter);
        }
    }

    for (i = n[k]; i <= m[k]; i++)
    {
        if (i == 1)
            continue;
        if (indexOfPrimes[i % (m[k] - n[k] + 1)] != 1)
            Console.WriteLine(i);
    }
    Console.WriteLine("\n");
}

这里带有变量k 的循环用于处理t 测试用例。当 m[k]>10^7 时,该算法需要大量时间来处理最大范围(即 100000)。

有没有办法不从2开始计算,而是直接从指定范围内计算?

有没有办法让我更快?

编辑:有人可以提供一个足够大的随机输入来测试我的算法。它总是给出Time Limit Exceeded,但是,它在我的笔记本电脑上运行只需 2.5 秒。

编辑:我在最大输入时将其减少到 1.5 秒。给我错误的答案。不明白为什么。

【问题讨论】:

  • 这是 SPOJ 的问题吗?从描述来看是这样的。
  • 是的,我收到了Time Limit Exceeded
  • 您的笔记本电脑可能比 SPOJ 电脑快 6 倍。

标签: performance algorithm c#-4.0 primes sieve-of-eratosthenes


【解决方案1】:

从算法的角度来看,你想做的是

  • 用任何方法找出 2 到 316 之间的素数
  • 使用这些素数筛选直到 100000 的所有数字,从而找到最高 100000 的素数
  • 使用 100K 个素数筛选给定范围,从而找到给定范围内的素数

用一个例子来说明最后一点,假设我们知道从 2 到 4 的所有素数,并且我们想找到 11 到 15 之间的所有素数。第一步是找到 2 之间的素数集和4,即{2,3}。现在我们使用该集合来筛选集合{11,12,13,14,15}

为此,我们注意到 6*2 是 2 在所需范围内的最小倍数,然后我们消除所有 2 的倍数,直到到达范围的末尾,因此消除了 12 和 14。

然后我们用 3 重复这个过程,消除 12(再次)和 15。范围内的剩余数字是 11 和 13,所以这些是 11 到 15 范围内的素数。

一个挑战是找到给定素数pNM 范围内的最小倍数。您可以通过将范围的低端除以p 并在必要时四舍五入来实现。例如,下面的代码找到最小的乘数x,使得p*x &gt;= N

int p, N, x;

x = N / p;         // integer division truncates, so x may be too small
if ( p * x < N )   // if p divides N, then p * x == N, 
   x++;            // otherwise we need to adjust x

Example 1: (N = 11, p = 2) ==> (x = 5, but 5*2<11, so x = 6)
Example 2: (N = 12, p = 3) ==> (x = 4, and 3*4==12, so x stays at 4)

【讨论】:

  • 我的范围不是静态的。它可以是 10-100000 或 100000-200000 或 100000000-100100000。但我想我明白了你的意思。首先,我应该得到sqrt(n[k]),对吧?
  • @SamarthAgarwal 316 是sqrt(100K),100K 是sqrt(10^10)。关键是如果你知道所有最高 100K 的素数,你可以筛选出最高 10^10 的任何范围。
  • 你是说我必须检查从 317 到 100k 的每个数字是否可以被 (2-317) 范围内的每个素数整除?
  • @SamarthAgarwal 2 到 317 的素数可用于筛​​选 318 到 100000 的数字。相当于在 100K 的数组上运行 sieve-of-eratosthenes 并在到达 @987654334 时停止@
  • @SamarthAgarwal 所以你需要一个大小为 (M-N+1) 的数组来表示从 N 到 M 的数字,并使用最高 100K 的素数来筛选该数组。
【解决方案2】:

大于界限lo的素数p的最小倍数是floor(lo/p)*p+p。您可以将其用作起点,而不是从 p.

【讨论】:

  • 错了;我忘了乘以 p。现在已经修好了。对不起。
  • 谢谢。您的回答帮助我将速度提高了 2 倍。但是我仍然得到错误的答案,但是,我所有的测试,无论它们多么大,都是完美的。
  • 我不会涉足你的代码。但是,如果您的答案很接近,那么您可能会在某处遇到错误;也许您没有标记范围内的最后一个复合材料。
  • 我也查过了,目前没找到。
猜你喜欢
  • 2018-11-27
  • 1970-01-01
  • 2010-11-01
  • 2016-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-15
  • 2021-03-17
相关资源
最近更新 更多