next up previous contents
Next: pi_other.c Up: Wie berechnet man mit Previous: Wie berechnet man mit   Contents

pi.c

Hier erklären wir kurz den Aufbau von pi.c.

Zuerst wird mit dem folgenden Befehl das Headerfile pvm3.h eingebunden. Dieses enthält den Sourcecode der PVM-Funktionen des Programms und lag der PVM-Distribution bei.

#include "pvm3.h"
Nach der Variablendeklaration werden einige Variablen initialisiert, wie zum Beispiel steps und nodes. Der Wert der Variable steps ist die Wurzel der Anzahl Punkte, die jeder Node berechnet. Dies, weil jeder Client steps * steps Punkte zugeteilt bekommt. nodes ist die Anzahl der beteiligten Nodes. Es werden nodes * nodes Tasks gestartet, damit jeder Rechner gleich viele Tasks bekommt:
steps = 100000;
nodes = 1;

Die folgenden Schleifen sorgen dafür, dass der Quelltext dazwischen nodes*nodes mal ausgeführt wird. Dabei ändern sich jeweils die Werte der Variablen x und y, welche als Koordinaten dienen und angeben, welches Quadrat man gerade bearbeitet:

for(x=0;x<=nodes-1;x++){ 
   for(y=0;y<=nodes-1;y++) {
      //Dieser Quelltext wird nodes*nodes mal ausgef\"uhrt. 
   }
}

Es ist nicht sinnvoll, ein Quadrat an einen Rechner weiterzugeben, wenn ohnehin alle darin enthaltenen Punkte innerhalb oder ausserhalb des Kreises liegen. Dies testen wir für jeden Eckpunkt. Wenn die vier Eckpunkte im Kreis liegen, dann liegen auch alle Punkte des Quadrates im Kreis. Mit den folgenden Programmzeilen wird das getestet. Ist ein Eckpunkt im Kreis, erhöht sich drin um 1:

q=x/nodes;
w=y/nodes;
z=q*q+w*w;
if (z<=1){
   drin++;
}

q=(x+1)/nodes;
w=y/nodes;
z=q*q+w*w;
if (z<=1){
   drin++;
}

q=x/nodes;
w=(y+1)/nodes;
z=q*q+w*w;
if (z<=1){
   drin++;
}

q=(x+1)/nodes;
w=(y+1)/nodes;
z=q*q+w*w;
if (z<=1){
   drin++;
}

Wenn drin nun grösser oder gleich 4 ist, dann muss man an der Variable resultat nichts verändern. Wenn drin kleiner oder gleich 0 ist, dann muss man $\frac{4}{nodes \cdot nodes}$ zum Resultat addieren:

if (drin>=4){

}	  
if (drin<=0){
   result=result+4/(nodes*nodes);	      
}

Wenn drin zwischen 0 und 4 liegt, das heisst, wenn nicht alle Punkte innerhalb oder ausserhalb des Kreises liegen, muss das Quadrat berechnet werden.

Mit der folgenden Zeile wird auf dem Node das Programm pi_other gestartet:

cc[x] = pvm_spawn("pi_other", (char**)0, 0, "", 1, &tid[y]);
Danach wird dem Node die Information gesendet, welches Quadrat er berechnen soll. Dies geschieht mit dem Array ort des Typs int. pvm_parent(); fragt die tid des Master-Prozesses ab, um dem Node den Absender der Nachricht mitzuteilen. So weiss dieser, an wen er später das Resultat zurücksenden muss.

pvm_initsend(PvmDataDefault); öffnet einen Puffer, in den man die Daten, die versendet werden sollen, speichern kann. Mit pvm_pkdouble(ort, 2,1); werden die Informationen in den Puffer geschrieben. Das Wort double bedeutet hier, dass man einen Wert des Typs double sendet. In der Klammer steht, dass der Array ort gesendet wird und dass dieser aus höchstens 2 Elementen besteht.

Mit dem Befehl pvm_send() wird der Inhalt des Puffers an den Node mit dem Tid tid[y] gesendet:

if ((1<=drin)&&(drin<=(3))){	      
   cc[x] = pvm_spawn("pi_other", (char**)0, 0, "", 1, &tid[y]); 
   if (cc[x] == 1){
      printf("Task erfolgreich an t%x uebergeben\n",tid[y]);
	
      count++;
	
      ort[0]=x;
      ort[1]=y;
		
      ptid = pvm_parent();       
      pvm_initsend(PvmDataDefault); 
      pvm_pkdouble(ort,2,1);
      pvm_send(tid[y], 1);
		
   } else
      printf("konnte pi_other auf t%x nicht starten\n",tid[x]; 
}

Nun wartet der Master auf die Resultate der Clients und wertet diese aus:

for (i=1;i<=count;i++){
   bufid=pvm_recv(-1, -1);                     
   pvm_bufinfo(bufid, &dum, &dum, &stid);       
   pvm_upklong(buf, 1, 1);
   // printf("Habe von t%x %f erhalten\n",tid[i], buf[0]);
   result=result+buf[0]/(steps*steps*nodes*nodes)*4;
   printf("sein result ist %f\n",result);
   pvm_initsend(PvmDataDefault);                
   pvm_send(stid, 0);
}

Wegen Problemen mit der Variablengrösse (siehe auch 13.4.1) haben wir nicht die Punkte, die im Kreis liegen summiert, sondern diejenigen, die nicht im Kreis sind. Um als Ausgabe wirklich $\pi $ zu erhalten, muss man noch die folgende Rechnung durchführen:

pi=4-result;

Nun hat man ein Resultat für $\pi $ berechnet, welches auf der Konsole ausgegeben sowie in eine Datei geschrieben wird:

printf("\npi = %e \n\n\n",pi);
datei = fopen("pi.txt","w");
fprintf(datei,"%e", pi);


next up previous contents
Next: pi_other.c Up: Wie berechnet man mit Previous: Wie berechnet man mit   Contents
Manfred Stock 2003-02-07