// compute pi by integrating f(x) = 4/(1 + x*x)     
// example program for colloq
// scalar version

import java.io.*;


public class ThreadDemo extends Thread {

  // default values of input parameters
  static final int  nDefault = 100;
  static final int  nThreadDefault = 4;

  // data common to all threads
  protected static int       nThreads;       // number of threads 
  protected static int       n;              // total number of points 
  protected static double    h;              // step size 
  protected static double[]  localsum;       // array with results 

  // thread private data
  protected  int       myid;


  // constructor for slave threads
  // creates a new thread with given id 
  public ThreadDemo(int threadID) {
    myid = threadID;
  } 
  
  // constructor for the master
  // starts the whole program
  public ThreadDemo(String[] args) {
    // get command line arguments
    try {
      n = Integer.parseInt(args[0]);
      nThreads = Integer.parseInt(args[1]);
    } catch (Exception e) {
      System.out.println("Fehlerhafte Parameter - verwende Default-Werte.");
      n = nDefault;
      nThreads = nThreadDefault;
    }
    
    // initialize data
    localsum = new double[nThreads];
    h = 1.0 / n;
    ThreadDemo[] threadList = new ThreadDemo[nThreads];
    
    // create threads, which all call the run method
    for (int i = 1; i < nThreads; i++) {
      threadList[i] = new ThreadDemo(i);
      threadList[i].start();
    }
    
    // work myself, as thread 0
    myid = 0;
    run();
    
    // wait for other threads */
    try {
      for (int i = 1; i < nThreads; i++) {
	threadList[i].join();
      }
    } catch (InterruptedException e) {
      System.out.println("got InterruptedException:");
      e.printStackTrace(System.out);
    }
    
    // add partial sums
    double sum = 0.0;
    for (int i = 0; i < nThreads; i++) {
      sum += localsum[i];
    }
    double pi = h * sum;
    
    // print the result
    System.out.println("pi computes to:" + pi);
    System.out.println("and is:        " + Math.PI);
  }

  // routine called by the threads after thread.start()
  // returns result in localsum[myid]
  public void run() {
    double x;
    localsum[myid] = 0.0;
    for (int i = myid; i < n; i += nThreads) {
      x = h * (i - 0.5);
      localsum[myid] += f(x);
    }
  }

  private double f(double x) {
    return 4.0 / (1.0 + x * x);
  }

  public static void main(String[] args) {
    ThreadDemo prog = new ThreadDemo(args);
  }
}