这个问题的目的是能够获得2.000.000的第一个素数,并且能够分辨出2.000.000的素数。
我们从这段代码开始:
#include <stdlib.h>
#include <stdio.h>
#define N 2000000
int p[N];
main(int na,char* arg[])
{
int i;
int pp,num;
printf("Number of primes to find: %d\n",N);
p[0] = 2;
p[1] = 3;
pp = 2;
num = 5;
while (pp < N)
{
for (i=1; p[i]*p[i] <= num ;i++)
if (num % p[i] == 0) break;
if (p[i]*p[i] > num) p[pp++]=num;
num += 2;
}
printf("The %d prime is: %d\n",N,p[N-1]);
exit(0);
}
现在我们被要求通过pragma omp进行此过程。这就是我到目前为止所做的:
#include <stdlib.h>
#include <stdio.h>
#define N 2000000
#define D 1415
int p[N];
main(int na,char* arg[])
{
int i,j;
int pp,num;
printf("Number of primes to find: %d\n",N);
p[0] = 2;
p[1] = 3;
pp = 2;
num = 5;
while (pp < D)
{
for (i=1; p[i]*p[i] <= num ;i++)
if (num % p[i] == 0) break;
if (p[i]*p[i] > num) p[pp++]=num;
num += 2;
}
int success = 0;
int t_num;
int temp_num = num;
int total = pp;
#pragma omp parallel num_threads(4) private(j, t_num, num, success)
{
t_num = omp_get_thread_num();
num = temp_num + t_num*2;
#pragma omp for ordered schedule(static,4)
for(pp=D; pp<N; pp++) {
success = 0;
while(success==0) {
for (i=1; p[i]*p[i] <= num;i++) {
if (num % p[i] == 0) break;
}
if (p[i]*p[i] > num) {
p[pp] = num;
success=1;
}
num+=8;
}
}
}
//sort(p, 0, N);
printf("El %d primer es: %d\n",N,p[N-1]);
exit(0);
}
现在让我解释一下我的“部分”解决方案,以及我的问题。
使用顺序代码获得第一个D素数,所以现在我可以检查大量数字的可分性。
每个线程都运行一个素数对角线,这样线程之间就没有依赖关系,也就不需要同步了。但是,这种方法的问题如下:
问题/困境是:
我怎么能知道何时生成了第2.000.000个素数?
提示: 我被告知我应该批量(假设)10.000个素数候选人。然后,当我不知道的事情发生时,我会知道最后一批10.000候选人包含2.000.000th prime,我可以用quicksort对它进行排序。
我希望自己明确表示,这是非常好的运动,我只是试了好几天。
答案 0 :(得分:2)
如果您只需要2000000个素数,则可以为每个找到的素数维持一个~4.1MB大小的比特阵列和翻转位。不需要排序。通过实现仅赔率表示方案将您的比特阵列大小减半。
在段中使用Sieve of Eratosthenes,其大小与sqrt(top_value_of_range)
成比例(或类似的东西 - 目标是在每个细分上执行大致相同的工作量)。对于n=2000000
,n*(log n + log(log n)) == 34366806
和prime[771]^2 == 34421689
(从0开始),因此,预先计算前771个素数。
每个工作人员也可以计算,因为它会翻转这些位,因此当它们全部完成时你将知道每个范围的计数,并且只需要扫描包含第2个第2个素数的一个范围。结束,找到那个素数。或者让每个工作人员根据其范围保持自己的比特阵列 - 你只需要保留一个,并且可以丢弃其他人。
计算Eratosthenes筛子的伪代码是:
Input: an integer n > 1
Let A be an array of bool values, indexed by integers 3, 5, ... upto n,
initially all set to true.
count := floor( (n-1)/2 )
for i = 3, 5, 7, ..., while i^2 ≤ n:
if A[i] is true:
for j = i^2, i^2 + 2i, i^2 + 4i, ..., while j ≤ n:
if A[j] is true:
A[j] := false
count := count - 1
Now all 'i's such that A[i] is true are prime,
and 'count' is the total count of odd primes found.
答案 1 :(得分:1)
我可以想到两种方法。
一旦你有了第二百万个素数的候选人,你的线程会继续计算低于你的候选人的素数,直到你没有素数丢失。然后你可以对素数列表进行排序,并从中获取第二百万分之一。
如果您的线程正在生成顺序素数块,它们应该分别维护块,然后可以将素数块重新组合成主列表。执行重组的线程可以在程序找到第2百万个素数后终止该程序。