
#include <omp.h>

// calculates prefix sums sequentially on u, where u is an m-element
// array

void seqprfsum(int *u,int m)
{  int i,s=u[0];
   for (i = 1; i < m; i++) {
      u[i] += s;
      s = u[i];
   }
}

// OMP example, calculating prefix sums in parallel on the n-element
// array x, in-place; for simplicity, assume that n is divisible by the
// number of threads; z is for intermedia storage, an array with length
// equal to the number of threads; x and z point to global arrays

void parprfsum(int *x, int n, int *z)
{
   #pragma omp parallel
   {  int i,j,me = omp_get_thread_num(),
          nth = omp_get_num_threads(),
          chunksize = n / nth,
          start = me * chunksize;
      seqprfsum(&x[start],chunksize);
      #pragma omp barrier 
      #pragma omp single 
      { 
      for (i = 0; i < nth-1; i++) 
         z[i] = x[(i+1)*chunksize - 1];
      seqprfsum(z,nth-1);
      }
      if (me > 0) {
         for (j = start; j < start + chunksize; j++) {
            x[j] += z[me - 1]; 
         }
      }
   }
}

int main()
{  int i,u[9] = {5,12,13,5,4,3,8,6,1}, z[3];
   parprfsum(u,9,z);
   for (i = 0; i < 9; i++) printf("%d\n",u[i]);
}

