实验二 基于MPI计算π值

实验二  基于MPI计算π值

一、实验题目:

用 MPI 集合通讯编程计算π的值。

二、实验目的
熟悉 MPI 编程的集合通讯调用,加深对其编程的理解。
三、实验环境
Linux Centos, 运行 MPI

四、程序设计

(一)源码:

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <mpi.h>

//计算圆周率积分公式中的被积函数值

double f(double x) {

    return 4.0 / (1.0 + x * x);

}

//梯形法则计算积分的近似值,base_length(梯形底边长度),num_intervals(梯形数量)和start(梯形起始位置)

double trapezoidal_integral(double base_length, int num_intervals, double start) {

    double integral = (f(start) + f(start + num_intervals * base_length)) / 2.0;

    for (int i = 1; i < num_intervals; i++) {

        double x_i = start + i * base_length;

        integral += f(x_i);

    }

    integral *= base_length;

    return integral;

}

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

    int rank, size;//进程等级、总进程数

    int num_intervals = 0;

    double base_length, local_integral, total_integral;

    MPI_Init(&argc, &argv);

    MPI_Comm_size(MPI_COMM_WORLD, &size);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    //等级为0,接收用户输入的区间数(梯形数),然后通过MPI_Bcast广播到所有进程。

    if (rank == 0) {

        printf("Enter the number of intervals: ");

        fflush(stdout);

        scanf("%d", &num_intervals);

    }

    MPI_Bcast(&num_intervals, 1, MPI_INT, 0, MPI_COMM_WORLD);

    //计算梯形底边长度base_length。

    base_length = 1.0 / (double)num_intervals;

    //为每个进程分配本地梯形数量(local_num_intervals)和起始、结束位置(local_start和local_end)。

    int local_num_intervals = num_intervals / size;

    int local_start = rank * local_num_intervals;

    int local_end = (rank == size - 1) ? num_intervals : (rank + 1) * local_num_intervals;

    //计算本地起始位置对应的x值(local_base_start)。

    double local_base_start = base_length * local_start;

    //使用trapezoidal_integral函数计算每个进程的本地积分值(local_integral)。

    local_integral = trapezoidal_integral(base_length, local_end - local_start, local_base_start);

   

    MPI_Reduce(&local_integral, &total_integral, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

    //等级为0的进程输出最终估计的π值。

    if (rank == 0) {

        printf("Estimated value of Pi: %.15f\n", total_integral);

    }

    //结束MPI环境

    MPI_Finalize();

    return 0;

}

(二)整体逻辑:

代码的整体实现逻辑是使用MPI并行计算框架和梯形积分法来估计π值。以下是实现逻辑的详细步骤:

初始化MPI环境:使用MPI_Init函数初始化MPI环境。这是使用MPI进行并行计算的第一步。

获取进程信息:使用MPI_Comm_size获取总进程数(size),使用MPI_Comm_rank获取当前进程的等级(rank)。

输入区间数:在等级为0的进程中,从用户那里接收区间数(梯形数),然后通过MPI_Bcast广播到所有进程。

计算梯形底边长度:将1除以总区间数,得到梯形底边长度base_length。

分配本地梯形:为每个进程分配一定数量的梯形,计算每个进程的本地梯形数量(local_num_intervals),起始位置(local_start)和结束位置(local_end)。

计算本地积分值:根据每个进程的起始位置,计算本地梯形积分值(local_integral)。这一步使用了trapezoidal_integral函数来计算每个进程的本地积分值。

汇总积分值:使用MPI_Reduce函数将所有进程的本地积分值相加,得到总积分值(total_integral)。

输出结果:等级为0的进程输出最终估计的π值。

结束MPI环境:使用MPI_Finalize函数结束MPI环境。

整体实现逻辑的关键在于将梯形积分法应用于计算π的近似值,并利用MPI并行计算框架将任务分发到多个进程上,以提高计算效率。通过将总区间数(梯形数)分配给多个进程,可以在保持计算精度的同时减少单个进程的计算负担。

(三)关键函数分析:

(1)、double f(double x):这个函数计算圆周率积分公式中的被积函数值,即 4 / (1 + x^2)。这是一个数学公式,用于计算π的近似值。

(2)、double trapezoidal_integral(double base_length, int num_intervals, double start):这个函数使用梯形法则计算积分的近似值。它接收3个参数:base_length(梯形底边长度),num_intervals(梯形数量)和start(梯形起始位置)。函数首先计算起始点和结束点的函数值之和的一半,然后遍历每个梯形,计算梯形顶边对应点的函数值。最后将梯形和乘以底边长度,得到积分近似值。

(3)、主函数:

首先,初始化MPI环境并获取进程等级(rank)和总进程数(size)。

等级为0的进程接收用户输入的区间数(梯形数),然后通过MPI_Bcast广播到所有进程。

计算梯形底边长度base_length。

为每个进程分配本地梯形数量(local_num_intervals)和起始、结束位置(local_start和local_end)。

计算本地起始位置对应的x值(local_base_start)。

使用trapezoidal_integral函数计算每个进程的本地积分值(local_integral)。

通过MPI_Reduce将所有进程的本地积分值相加,得到总积分值(total_integral)。

等级为0的进程输出最终估计的π值。

结束MPI环境。

程序的整体逻辑是将梯形积分法应用于计算π的近似值。通过MPI并行计算,每个进程负责一部分梯形的计算,并将结果汇总以获得总的积分值。梯形数量越多,计算结果越接近真实的π值。

(四)、Linux命令:

Ls:列出当前目录中的所有文件或目录

Rm:删除文件或空目录

Rz:上传文件

mpicc -o pi_mpi 1.c 编译程序

mpirun -np 4 ./pi_mpi 运行程序

五、运行结果

mpirun -np 4 ./pi_mpi

六、实验心得

代码中程序编写技巧

  1. 包含头文件:代码中包含了一些标准头文件和MPI头文件,以便使用相关的函数和类型。例如,<stdio.h><stdlib.h><math.h>是标准头文件,<mpi.h>是MPI头文件。
  2. 积分函数定义:代码中定义了被积函数f(x),它返回一个double类型的结果。这个函数用于计算圆周率积分公式中的被积函数值。
  3. 梯形法则计算积分:代码中定义了trapezoidal_integral函数,它使用梯形法则来计算积分的近似值。它接受梯形底边长度、梯形数量和起始位置作为参数,并返回近似的积分值。
  4. MPI初始化:通过调用MPI_Init(&argc, &argv)来初始化MPI。argcargv参数允许将命令行参数传递给MPI初始化函数。
  5. 获取进程等级和总进程数:使用MPI_Comm_size(MPI_COMM_WORLD, &size)MPI_Comm_rank(MPI_COMM_WORLD, &rank)函数分别获取通信域中的进程数量和当前进程的等级。
  6. 输入参数广播:在等级为0的进程中,使用标准输入函数(如scanf)获取用户输入的梯形数量,并使用MPI_Bcast函数将其广播给所有进程。
  7. 任务分配:根据进程等级,计算每个进程的本地梯形数量、起始位置和结束位置。使用MPI_Bcast广播梯形底边长度给所有进程。
  8. 本地积分计算:在每个进程中,使用trapezoidal_integral函数计算本地积分值,使用本地起始位置和梯形数量计算本地积分范围。
  9. 全局积分汇总:使用MPI_Reduce函数将每个进程的本地积分值汇总到等级为0的进程中,使用MPI_SUM操作进行求和。
  10. 输出结果:在等级为0的进程中,输出最终估计的π值。
  11. 结束MPI环境:在程序的最后通过调用MPI_Finalize()函数来结束MPI。

函数使用技巧

  1. MPI初始化和结束:在程序的开始和结束分别调用MPI_InitMPI_Finalize函数来初始化和结束MPI环境。这确保了MPI库的正确使用,并且每个进程都在正确的时间点开始和结束MPI环境。
  2. 进程等级和总进程数获取:通过调用MPI_Comm_sizeMPI_Comm_rank函数分别获取通信域中的进程数量和当前进程的等级。这些信息对于进程间的任务分配和协调非常重要。
  3. 数据广播:使用MPI_Bcast函数将梯形数量和梯形底边长度从等级为0的进程广播给其他进程。这确保了所有进程都具有相同的参数值,以便进行一致的计算。
  4. 全局规约:使用MPI_Reduce函数将每个进程的本地积分值汇总到等级为0的进程中。使用MPI_SUM操作进行求和。这允许在主进程中进行最终结果的计算和输出。
  5. 并行计算:在每个进程中使用trapezoidal_integral函数计算本地积分值。通过将工作分布给多个进程,实现并行计算,提高了计算效率。

可能出错的地方

  1. 输入合法性验证:代码中未对用户输入的梯形数量进行验证和范围检查。在实际应用中,可能需要添加对用户输入的合法性验证的代码。
  2. 梯形数量和进程数量的关系:代码中假设梯形数量是进程数量的整数倍,这样可以确保每个进程获得相等数量的梯形。如果梯形数量不能被进程数量整除,可能需要使用更复杂的任务划分策略。
  3. 积分方法的精确性:梯形法则是一种数值积分方法,其结果是对积分的近似值。对于更高精度的计算,可能需要使用其他数值积分方法。
  4. 并行性能:在这个简单的示例中,每个进程都进行了积分计算,然后将结果汇总到等级为0的进程中。这种并行计算方式可能不是最有效的,并且可能存在负载不均衡的问题。在实际应用中,可能需要进行更复杂的任务分配和负载平衡。
  5. 错误处理:MPI函数返回的错误代码可以用于检测并处理MPI调用中的错误。在实际的MPI程序中,通常需要对MPI函数的返回值进行检查,并根据错误码采取相应的错误处理措施。

在本次实验中,我们使用了MPI并行编程方法来估计π值。通过实验,我们学习了MPI的基本概念、函数和编程方法。以下是实验心得:

1.MPI的重要性:并行计算在高性能计算领域具有重要意义。MPI作为一种通用的并行编程方法,可以帮助我们在多个处理器上分发任务,以提高计算效率。

2.MPI函数的使用:在实验过程中,我们学习了MPI的基本函数,例如MPI_Init、MPI_Comm_size、MPI_Comm_rank、MPI_Bcast、MPI_Reduce等。这些函数有助于我们控制并行计算过程,分发任务并收集结果。

3.代码结构:通过将代码分解成不同的函数,如f和trapezoidal_integral,我们可以使代码结构更清晰,易于理解和维护。同时,将关键算法和MPI相关代码分离,有助于提高代码的可复用性。

4.调试与优化:在进行实验时,我发现了一个计算误差的问题,并通过仔细审查代码,成功解决了问题。这说明在进行并行编程时,要特别注意代码的正确性,确保计算结果的准确性。

5.性能与精度权衡:在实验中,我们学习了如何根据计算资源和期望精度选择合适的区间数。较大的区间数可以提高计算精度,但可能导致计算时间过长。因此,在实际应用中,需要根据需求合理选择参数,实现性能与精度之间的平衡。

总之,通过本次实验,我掌握了MPI并行编程的基本知识和技巧,加深了对并行计算的理解。在未来的工作中,我可以运用所学知识解决实际问题,提高计算效率。

  • 17
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值