2017-10-27 5 views
0

Diese C MPI-Anwendung für die Pi-Approximation gibt immer das gleiche Ergebnis pro Problemgröße aus, dh die Anzahl der zufällig generierten Punkte (npts).Warum ist das Ergebnis bei der Ausführung dieser C MPI-Anwendung für die Pi-Approximation immer gleich?

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include "mpi.h" 

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

    int myid,nprocs; 

    double PI25DT = 3.141592653589793238462643; 

    long long npts = 1e10; 

    long i,mynpts; 

    long double f,sum,mysum; 
    long double xmin,xmax,x; 

    MPI_Init(&argc,&argv); 
    MPI_Comm_size(MPI_COMM_WORLD,&nprocs); 
    MPI_Comm_rank(MPI_COMM_WORLD,&myid); 

    if (myid == 0) { 
    mynpts = npts - (nprocs-1)*(npts/nprocs); 
    } else { 
    mynpts = npts/nprocs; 
    } 

    mysum = 0.0; 
    xmin = 0.0; 
    xmax = 1.0; 

    srand(myid); 

    for (i=0; i<mynpts; i++) { 
    x = (long double) rand()/RAND_MAX*(xmax-xmin) + xmin; 
    mysum += 4.0/(1.0 + x*x); 
    } 

    MPI_Reduce(&mysum,&sum,1,MPI_LONG_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD); 

    if (myid == 0) { 
    f = sum/npts; 
    printf("PI calculated with %lld points = %.16f \n",npts,f); 
    printf("Error is: %.16f \n",fabs(f-PI25DT)); 
    } 

    MPI_Finalize(); 
} 

Dies ist der Ausgang. Ich denke, das Ergebnis sollte bei jedem Lauf der Anwendung ein wenig abweichen. Ich führe es auf einem Cluster mit 128 Knoten aus.

$ mpicc pi.c -o /mnt/cluster_128/pi 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 
$ mpirun -np 128 --hostfile hosts_4cores_128.mpi /mnt/cluster_128/pi 
PI calculated with 10000000000 points = 3.1415901444578158 
Error is: 0.0000025091319773 

Antwort

3

Sie Impfen der hier PRNG:

srand(myid); 

myid ein Wert, der durch Ihren Anruf MPI_Comm_rank() und Sie sind daran interessiert sind nur in den Ergebnissen für myid == 0, so ist dies immer der gleiche Wert eingestellt ist . Seeding den gleichen Wert ergibt die gleiche Folge von "zufälligen" Zahlen.

Verwenden Sie die gemeinsame Idiom statt Impfen:

#include <time.h> 
#include <stdlib.h> 

[...] 

srand(time(0)); 
+0

Es ist eine Ausgabe von 'MPI_Comm_rank' –

+0

@ WeatherVane ist es gut für die Seeding? Dann werde ich diese Antwort löschen ... –

+0

Nein, weil der Code nur die Ergebnisse druckt, wenn 'if (myid == 0)' –

1

Ihr Code druckt nur kein Ergebnis, wenn if (myid == 0), die zeigt Ihre RNG Samen nutzlos ist.

Ich schlage vor,

srand((unsigned)time(NULL)); 
1

Die bestehenden Antworten zeigen bereits in die richtige Richtung, aber ich denke, ihre Erklärung nicht ganz richtig ist.

Das Problem ist, wie bereits gesagt, auf dem RNG-Saatgut. Sie verwenden myid als Startwert für srand, der immer eine Zahl zwischen 0 und N-1 ist (also die Anzahl der Ränge, d. H. Die Nummer, die Sie an mpiexec -np N executable übergeben). Dies ist deterministisch: Es ändert sich nicht für verschiedene Ausführungen.

Daher sind alle N-Prozesse gehen, um die gleiche Menge von Samen, und die erzeugten Zufallszahlen sein werden, das gleiche gilt für die gleiche Anzahl von Prozessen zu erstellen:

  • für einen einzelnen Prozess (N = 1): Startwert ist immer 0
  • Für fünf Prozesse (N = 5): Startwerte sind immer 0, 1, 2, 3 und 4 in jedem Prozess. Und so weiter.

Die MPI_Reduce kollektiven präsentiert die Teilergebnisse von jedem Prozess (die die gleichen Werte durch die Zufallszahl wobei gleiche Ausbeute) und druckt den grand sum im Wurzelprozess (myid=0). Die Tatsache, dass der Prozess mit myid das Ergebnis druckt, spielt keine Rolle, da es andere N-1-Prozesse mit unterschiedlichen myid Werten gibt, die zum endgültigen Ergebnis beitragen, das gedruckt wird.

Kleines Beispiel für zwei Prozesse, mit myid:

  • Rank 0: srand(0), Teilsumme (mysum) berechnet, anderer Prozesse Teilsumme in sum Variable ansammelt (Sie 0 als Root angeben Prozess in MPI_Reduce 7. Argument. Druckt das Ergebnis (myid==0 ist true).

  • Rang 1: srand(1), berechnet partielle Summe (mysum) sendet es an MPI_Reduce Root-Prozess (0). Das Ergebnis wird nicht gedruckt (myid==0 ist false).

Das Wichtigste, was Sie mit MPI verstehen müssen, ist, dass Sie in der Regel ein einzelnes Programm mit mehreren Prozessen ausgeführt werden, und jedes dieses Verfahren ein anderes Umgebung (Ausgabeargument der MPI_Comm_rank) erhalten.

Verwandte Themen