MPI-筛选法求素数

595 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情

素数

素数也叫质数,指在大于1的自然数中,除了1和它本身以外不再有其他因数。例如10以内的素数有2、3、5、7

筛选法求质数

image.png

不使用mpi

#include<stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
void main()
{
    int N = 100;
    char* identifies = (char*)malloc(sizeof(char)*N);
    memset(identifies, 0, N);
    int i,j,k;
    for(i=2;i<=(int)(sqrt(N));i++)     //从2-10作为最小值开始筛选
    {
        for(j=2;j*i<N;j++)   //找出最小数的倍数
        {
            identifies[i*j]=1;     //把最小数的倍数赋值1
        }
    }
    for(k=2;k<N;k++)   //因为1不是素数,所以从2开始遍历输出素数
    {
        if(identifies[k]==0)       //在a数组中如果数组元素是0,那么相应下标就是素数
        {
            printf("%4d",k);
        }
    }
}

运行结果:

2   3   5   7  11  13  17  19  23  29  31  37  41  43  47  53  59  61  67  71  73  79  83  89  97

使用MPI方法

MPI计算素数时包括划分计算区域、处理器之间的数据通信(Bcast)、数据收集(Reduce)

#include <stdio.h>
#include <mpi.h>
#include <string.h>         //包含memset
#include <stdlib.h>
#define BLOCK_LOW(process_rank, n_numbers, process_number) (n_numbers/process_number*process_rank)
#define BLOCK_HIGH(process_rank, n_numbers, process_number) (n_numbers/process_number*(process_rank+1)-1)


int main(int argc, char** argv) {

    MPI_Init(&argc, &argv);                 
    int rank, size, local_size, index;                    //local_size是划分计算区域
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    //确定计算区域
    int n_numbers = 100;                                         //100以内的素数
    int low  = 1 + BLOCK_LOW(rank, n_numbers, size);            //素数从2开始计算
    int high = 1 + BLOCK_HIGH(rank, n_numbers, size);
    local_size = high - low + 1;

    char* mark = (char*)malloc(sizeof(char)*local_size);         //使用char节省空间
    memset(mark, 0, local_size);
    index = 1;
    int k = 2;

    while (k*k < n_numbers) {
        for (int i = low; i <= high; i++) {
            if(i%k == 0 && i != k) {  //不能删掉自己
                mark[i-low] = 1;
            }
        }
        
        //找下一个素数k
        if(!rank) {
            while (mark[++index]);
            k = index + 1; 
        }
        MPI_Bcast(&k, 1, MPI_INT, 0, MPI_COMM_WORLD); //将素数广播出去
    }

    int count = 0, global_count = 0;


    printf("rank = %d的素数有: ", rank);
    for (int i = 0; i < local_size; i++) {
        count += 1- mark[i];
        if(!mark[i]&& (i+low)!=1)    printf("%d ", i+low);
    }
    printf("\n");
    MPI_Reduce(&count, &global_count, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
    if (!rank) {
        printf("一共有%d个素数\n", global_count-1);
    }

    MPI_Finalize();
}

宏定义中的BLOCK_LOW和BLOCK_HIGH是为了划分每个进程的计算空间。 MPI_Reduce会收集每个处理器发来的数据,然后更具Operation(这里是MPI_SUM)将其规约成一个数字 建议读者手动敲下代码,这样才能理解每个参数、每行代码的用处。

运行结果:

rank = 0的素数有: 2 3 5 7 11 13 17 19 23 
rank = 2的素数有: rank = 1的素数有: 29 31 37 41 43 47 
53 59 61 67 71 73 
rank = 3的素数有: 79 83 89 97 
一共有25个素数