#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <pvm3.h>
#include "func.h"
/*
* Find the area to the tolerance.
*/
static double find(double x1, double y1, double x2, double y2, double tol)
{
/* Compute the midpoint from the funcion. */
double midx = (x1 + x2) / 2;
double midy = f(midx);
/* Estimate the midpoint from the y value. */
double midest = (y1 + y2) / 2;
/* See if we're getting close. */
if(fabs(midy - midest) <= tol)
/* Will do. Compute the area using the midy, since we
found it. Two trapazoids algebraically simplified. */
return 0.25*(x2-x1)*(y1 + y2 + 2*midy);
else
/* Subdivide and try again. */
return find(x1, y1, midx, midy, tol) +
find(midx, midy, x2, y2, tol);
}
#define INITMAX 20
int main(int argc, char **argv)
{
int cc, tid;
/* Fine argument whine. */
if(argc < 5) {
printf("Usage: %s startx endx tol nreg funcargs*\n",
argv[0]);
exit(2);
}
/* Get the args. */
char *pname = argv[0];
double start = atof(argv[1]);
double end = atof(argv[2]);
double tol = atof(argv[3]);
int nreg = atoi(argv[4]);
argc -= 5; argv += 5;
if(argc > INITMAX) {
printf("Function init limited to %d args.\n", INITMAX);
exit(4);
}
/* Sanity. */
if(tol < 0.0000000001) {
printf("Tolerance to too small or negative.\n");
exit(3);
}
if(nreg < 1) {
printf("Number of regions is nonpositive.\n");
exit(4);
}
if(end < start) {
double t = start;
start = end;
end = t;
}
/* Spawn a worker for each processor other than ourselves. */
int nhost, narch;
struct pvmhostinfo *hostp;
pvm_config( &nhost, &narch, &hostp );
if(nhost > nreg) nhost = nreg;
int tids[nhost - 1];
if(nhost > 1) {
char buf[100];
strcat(strcpy(buf, pname), "_slave");
cc = pvm_spawn(buf, 0, 0, "", nhost - 1, tids);
if(cc <= 0) {
/* Nothing was spawned. Whine about it. */
pvm_perror("Spawn failed");
pvm_exit();
exit(5);
}
if(cc != nhost - 1) {
/* At least one spawn failed. Reduce the number
of regions to what we could get. */
nhost = cc + 1;
printf("Unable to spawn all workers. Reducing "
"to %d.\n", nhost);
}
/* Send out the function init information. */
int n;
pvm_packf("%+ %d", PvmDataDefault,argc);
for(n = 0; n < argc; n++) {
int len = strlen(argv[n]);
pvm_pkint(&len, 1, 1);
pvm_pkstr(argv[n]);
}
pvm_mcast(tids, nhost - 1, 1);
}
/* Initialize the function. */
finit(argc, argv);
/* Divide into to nreg regions and send 'em out. */
double x = start;
double inc = (end - start) / nreg;
int i;
for(i = nreg; i--;) {
double newx = i ? x + inc : end;
pvm_packf("%+ %lf %lf %lf ",
PvmDataDefault, x, newx, tol);
int nx = pvm_putinfo("work", pvm_getsbuf(),
PvmMboxMultiInstance|PvmMboxOverWritable);
//printf("Index %d: %g %g\n", nx, x, newx);
x = newx;
}
/* Execute regions until all have been taken care of. */
double tot = 0.0;
while(1) {
int bid = pvm_recvinfo
("work", 0, PvmMboxFirstAvail|PvmMboxReadAndDelete);
//printf("bid = %d\n", bid);
if(bid < 0) break;
double startx, endx, tol;
pvm_unpackf("%lf %lf %lf ", &startx, &endx, &tol);
tot += find(startx, f(startx), endx, f(endx), tol);
}
/* Collect the others. */
for(i = 0; i < nhost - 1; ++i) {
int rn = pvm_recv(-1, 3);
double portion;
pvm_upkdouble(&portion, 1, 1);
tot += portion;
}
printf("Integral from %g to %g = %g (tol %g)\n",
start, end, tot, tol);
pvm_exit();
exit(0);
}