如@LaryxDecidua所指出的那样,MPFR数字使用堆上的动态内存,因此不能直接用于MPI操作。但是,如果您可以使用MPFR版本4.0.0或更高版本,则可以使用MPFR函数
mpfr_fpif_export
将数字序列化为线性内存缓冲区,并使用MPI发送该缓冲区。接收端可以通过调用
mpfr_fpif_import
来恢复原始数字。这两个函数都在
FILE *
句柄上操作,因此您还需要使用
open_memstream
和/或
fmemopen
将文件句柄映射到内存缓冲区。不幸的是,序列化的数字的长度不仅取决于精度,还取决于值(例如值0占用的字节数较少),因此需要每个排名固定缓冲区大小的组通信(例如
MPI_Scatter
或
MPI_Gather
)将无法使用。请改用
MPI_Send
和
MPI_recv
对。
这是一个完整的C++17示例,其中包含mpreal
,为C++代码库提供了与MPFR数字交互的良好接口:
#include <cstdio>
#include <iostream>
#include <mpi.h>
#include <mpreal.h>
#include <numeric>
#include <optional>
int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
std::vector<mpfr::mpreal> real_vec{world_rank, M_PI};
char *send_buf;
size_t send_buf_size;
FILE *real_stream = open_memstream(&send_buf, &send_buf_size);
for (auto &real : real_vec) {
mpfr_fpif_export(real_stream, real.mpfr_ptr());
}
fclose(real_stream);
std::optional<std::vector<size_t>> send_buf_size_vec;
if (world_rank == 0) {
send_buf_size_vec = std::vector<size_t>(world_size);
}
MPI_Gather(&send_buf_size, 1, MPI_UNSIGNED_LONG, (send_buf_size_vec ? send_buf_size_vec->data() : nullptr), 1,
MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
if (world_rank != 0) {
MPI_Send(send_buf, send_buf_size, MPI_BYTE, 0, 0, MPI_COMM_WORLD);
} else {
size_t recv_buf_size = std::accumulate(send_buf_size_vec->begin(), send_buf_size_vec->end(), 0UL);
std::vector<char> recv_buf(recv_buf_size);
auto all_buf_it = recv_buf.begin();
std::memcpy(&*all_buf_it, send_buf, send_buf_size);
all_buf_it += (*send_buf_size_vec)[0];
MPI_Status status;
for (int i = 1; i < world_size; ++i) {
MPI_Recv(&*all_buf_it, (*send_buf_size_vec)[i], MPI_BYTE, i, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
all_buf_it += (*send_buf_size_vec)[i];
}
real_stream = fmemopen(recv_buf.data(), recv_buf.size(), "rb");
std::vector<mpfr::mpreal> all_real_vec(world_size * real_vec.size());
for (auto &real : all_real_vec) {
mpfr_fpif_import(real.mpfr_ptr(), real_stream);
}
fclose(real_stream);
std::cout << "Read values:" << std::endl;
for (auto &real : all_real_vec) {
std::cout << real << std::endl;
}
}
MPI_Finalize();
return 0;
}
MPI_Op_create()
进行注册。请参见这里。 - Hristo Iliev