MPI和OpenMP实现蒙特卡罗算法

MPI和OpenMP实现蒙特卡罗算法

一、蒙特卡洛算法介绍

  1. 基本思想

    当所求解问题是某种随机事件出现的概率,或者是某个随机变量的期望值时,通过某种“实验”的方法,以这种事件出现的频率估计这一随机事件的概率,或者得到这个随机变量的某些数字特征,并将其作为问题的解。

  2. 数学应用:

    通常蒙特·卡罗方法通过构造符合一定规则的随机数来解决数学上的各种问题。对于那些由于计算过于复杂而难以得到解析解或者根本没有解析解的问题,蒙特·卡罗方法是一种有效的求出数值解的方法。一般蒙特·卡罗方法在数学中最常见的应用就是蒙特·卡罗积分。

  3. 案例:

    通过在正方形内随机撒点,落在圆内的点 / 落在正方形内的点,就约等于圆的面积 / 正方形的面积 = π 4 \frac{\pi}{4} 4π,随着撒点的数量增多, π \pi π的数值越来越接近真实值
    N 圆 N 正 方 形 ≈ S 圆 S 正 方 形 = π 4 ( N 为 点 的 数 量 , S 为 面 积 ) \frac{N_圆}{N_{正方形}}\approx \frac{S_圆}{S_{正方形}}=\frac{\pi}{4}\quad (N为点的数量,S为面积) NNSS=4π(NS)

二、MPI实现蒙特卡罗算法计算 π \pi π

  1. 首先要配置要MPI多节点集群环境,没有配置好的可以参考我的前几篇博客

  2. 原理

    1. 生成0-1内的随机数 x , y x,y x,y记为 ( x , y ) (x,y) (x,y),总共生成的点数为 N N N
    2. 计算每一个 ( x , y ) (x,y) (x,y)是否满足 x 2 + y 2 ≤ 1 x^2+y^2 \le 1 x2+y21,将符合条件的点数记为 C C C
    3. π \pi π的近似值可以看作 4 C N \frac{4C}{N} N4C
  3. 运行

    1. 编写profile文件,与上一节一样
    node01:2
    node02:2
    
    1. 编写源代码文件mpimc.cpp,两个虚拟机都需要

    2. 编译mpimc.cpp文件,两个虚拟机都需要编译

    mpic++ mpimc.cpp -o mpimc
    
    1. mpi多节点运行,-n参数推荐为2,只有main节点运行
    mpiexec -f profile -n 2 ./mpimc
    
  4. 运行结果

image-20220314084422660

  1. 代码
#include <iostream>
#include "mpi.h"

using namespace std;
const int maxn = 1e6; //随机点数量

MPI_Status status;
int main(int argc, char *argv[]) {
    int pCnt, pId, slaves, source, dest;
    int cnt, n, offset;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &pId);
    MPI_Comm_size(MPI_COMM_WORLD, &pCnt);

    slaves = pCnt - 1;
    offset = maxn / slaves;
    if(pId == 0) {
        for(dest = 1; dest <= slaves; dest++) {
            MPI_Send(&offset, 1, MPI_INT, dest, 1, MPI_COMM_WORLD);
            MPI_Send(&n, 1, MPI_INT, dest, 1, MPI_COMM_WORLD);
        }
        cnt = 0;
        for(int i = 1; i <= slaves; i++) {
            source = i;
            MPI_Recv(&offset, 1, MPI_INT, source, 2, MPI_COMM_WORLD, &status);
            MPI_Recv(&n, 1, MPI_INT, source, 2, MPI_COMM_WORLD, &status);
            cnt += n;
        }

        double pi = 4.0 * cnt / maxn;
        cout << "PI is " << pi << endl;
    }

    if(pId > 0) {
        source = 0;
        MPI_Recv(&offset, 1, MPI_INT, source, 1, MPI_COMM_WORLD, &status);
        MPI_Recv(&n, 1, MPI_INT, source, 1, MPI_COMM_WORLD, &status);
        n = 0;
        srand(time(NULL));
        for(int i = 0; i < offset; i++) {
            // 生成0-1内的随机数
            double x = (double)rand() / RAND_MAX;
            double y = (double)rand() / RAND_MAX;
            if(x * x + y * y <= 1)
                n++;
        }
        MPI_Send(&offset, 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
        MPI_Send(&n, 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
    }

    MPI_Finalize();
    return 0;
}

三、OpenMP实现蒙特卡罗算法计算 π \pi π

  1. 不需要MPI集群环境,只需要一个节点就行
  2. 原理(同上)
  3. 编译运行
g++ ompmc.cpp -fopenmp -o ompmc
./ompmc
  1. 运行结果

image-20220314085549202

  1. 代码
#include <iostream>
#include <pthread.h>
#include <omp.h>
using namespace std;
const int maxn = 1e6; //随机点数量


double dis(double x, double y) {
    return x * x + y * y;
}

int main(int argc, char *argv[]) {
    int cnt = 0;
    double x, y;
    int i;

    omp_set_num_threads(omp_get_num_procs());
    srand48(time(NULL));

    #pragma omp parallel for private(i)
    for(i = 0; i < maxn; i++) {
        // 生成0-1内的随机数
        x = (double)rand() / RAND_MAX;
        y = (double)rand() / RAND_MAX;
        if(dis(x, y) <= 1) cnt++;
    }
    double pi = 4.0 * cnt / maxn;
    cout << "Pi is " << pi << endl;
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值