admin管理员组文章数量:1389768
I want to have the global minimum (floating point types) across all MPI ranks and proceed only on the rank which computed the local minimum.
Specifically, can we compare the global and local minimum for exact equality (==)? Or is it possible that there can occur floating point errors in the reduction itself?
#include <iostream>
#include <mpi.h>
int main(int argc, char** argv) {
MPI_Init(&argc, &argv);
int rank;
double minDistance = 100.0 + rank;
double globalMinDistance;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Reduce to find the global minimum
MPI_Reduce(&minDistance, &globalMinDistance, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD);
// Can i safely compare the doubles here with ==?
if (minDistance == globalMinDistance) {
std::cout << "Rank " << rank << " has the globally minimum distance: " << globalMinDistance << std::endl;
}
MPI_Finalize();
return 0;
}
I want to have the global minimum (floating point types) across all MPI ranks and proceed only on the rank which computed the local minimum.
Specifically, can we compare the global and local minimum for exact equality (==)? Or is it possible that there can occur floating point errors in the reduction itself?
#include <iostream>
#include <mpi.h>
int main(int argc, char** argv) {
MPI_Init(&argc, &argv);
int rank;
double minDistance = 100.0 + rank;
double globalMinDistance;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Reduce to find the global minimum
MPI_Reduce(&minDistance, &globalMinDistance, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD);
// Can i safely compare the doubles here with ==?
if (minDistance == globalMinDistance) {
std::cout << "Rank " << rank << " has the globally minimum distance: " << globalMinDistance << std::endl;
}
MPI_Finalize();
return 0;
}
Share
Improve this question
asked Mar 13 at 14:42
MathieuMathieu
3327 bronze badges
20
|
Show 15 more comments
3 Answers
Reset to default 2There should be no roundoff in doing a minimum reduction. Your code looks safe to me. Have you tested it?
However, you are testing globalMinDistance
on each process, while the value is only set on rank zero. Use an Allreduce
.
Floating point numbers are not broken, they just have finite precision.
You must be aware of rounding errors. In particular (a + b) + c
is not always the same as a + (b + c)
. Assignent however, is not subject to rounding errors.
float x = 0.3;
float y;
y = x;
std::cout << (x == 0.3);
std::cout << (y == 0.3);
std::cout << (y == x);
The last line prints 1
, you can count on that. The lines before suffer from finite precision of float
and print 0
.
If you assume the reduction is only based on comparison via <
and assignment you can expect ==
to yield the correct result.
Independent of the discussion regarding floating point operations, and the issue about using reduce vs. allreduce that @VictorEijkhout pointed out, your approach has another issue. With your approach, you have no guarantee that you will determine a single process contributing the minimal value. Multiple processes might accidentally have the same minimal value. But, MPI has a way more elegant solution for your problem, which will also provide you always a single solution: You can use minloc reduction.
The following code will always print exactly one line with "minloc distance", but will print one line per process with "minimal distance", if you execute as ./a.out 0
.
#include <iostream>
#include <cstdlib>
#include <mpi.h>
struct minloc{
double value;
int loc;
};
int main(int argc, char** argv) {
MPI_Init(&argc, &argv);
int rank, alpha=1;
if (argc>1) alpha = atoi(argv[1]);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
minloc localMinloc = {100.1 - rank*alpha, rank}, globalMinloc;
// Reduce to find the global minimum
MPI_Allreduce(&localMinloc, &globalMinloc, 1, MPI_DOUBLE_INT, MPI_MINLOC, MPI_COMM_WORLD);
if (rank == globalMinloc.loc) {
std::cout << "Rank " << rank << " has the globally miniloc distance: " << globalMinloc.value << std::endl;
}
if (localMinloc.value == globalMinloc.value) {
std::cout << "Rank " << rank << " has the globally minimum distance: " << globalMinloc.value << std::endl;
}
MPI_Finalize();
return 0;
}
Produces output like:
$ mpirun -np 4 ./a.out 0
Rank 3 has the globally minimum distance: 100.1
Rank 0 has the globally miniloc distance: 100.1
Rank 0 has the globally minimum distance: 100.1
Rank 1 has the globally minimum distance: 100.1
Rank 2 has the globally minimum distance: 100.1
$ mpirun -np 4 ./a.out 1
Rank 3 has the globally miniloc distance: 97.1
Rank 3 has the globally minimum distance: 97.1
本文标签: cfloating point error in MPIReduce possibleStack Overflow
版权声明:本文标题:c++ - floating point error in MPI_Reduce possible? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744695349a2620243.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
(1/3)*3
isn't1
,(1.0/3.0)*3.0
isn't1.0
. The question of whether the floating-point values that you calculated are close enough to the corresponding real-number values that you're thinking of can't be answered without knowing and exploring how you calculated the values in question. – Pete Becker Commented Mar 13 at 14:49double ratio = 1.0/3.0; if (ratio == 1.0/3.0) { do_sometthing(); }
might not calldo_something()
. That's because the compiler is allowed to do floating-point math at higher precision, until you store the resulting value. So, typically,ratio
will be 64 bits wide, but1.0/3.0
might be 80 bits wide. So don't skip intermediate stores if you care about equality tests. – Pete Becker Commented Mar 13 at 14:53