import java.lang.Double;


public class stream {


		int  N;
		int M;
		int  NTIMES;
		int  OFFSET;
		String  HLINE ;
		int precision;

		double[] a ;
		double[] b;
		double[] c;
		String[] label;

		double[]	avgtime;
		double[]	maxtime;
		double[]	mintime;
		double[]	bytes;
		Double tmp;
		double FLT_MAX;

		public stream() {
			N	=20000000;
			M = 20;
			NTIMES	=10;
			OFFSET	=0;
			HLINE= "-------------------------------------------------------------";
			precision = 8; // java uses 8bytes per DOUBLE PRECISION word

			tmp=  new Double(0);
			FLT_MAX =tmp.longBitsToDouble(0x7fefffffffffffffL);


			a  = new double[N+OFFSET];
			b  = new double[N+OFFSET];
			c  = new double[N+OFFSET];

			label = new String[4];
			label[0] ="Copy:      ";
			label[1] ="Scale:     ";
			label[2] ="Add:       ";
			label[3] ="Triad:     ";

			avgtime = new double[4];
			maxtime = new double[4];
			mintime  = new double[4];

			mintime[0] = FLT_MAX;
			mintime[1] = FLT_MAX;
			mintime[2] = FLT_MAX;
			mintime[3] = FLT_MAX;

			bytes= new double[4];
			bytes[0] =  2 * precision * N;
			bytes[1] =  2 * precision * N;
			bytes[2] =  3 * precision * N;
			bytes[3] =  3 * precision * N;

			int			quantum;
			int			BytesPerWord;
			int	j, k;
			double		scalar;
			double t;
			double[][] times = new double[4][NTIMES];

			/* --- SETUP --- determine precision and check timing --- */

			System.out.println(HLINE);
			BytesPerWord = precision;
			System.out.println("This system uses " + BytesPerWord+" bytes per DOUBLE PRECISION word." );

			System.out.println(HLINE);
			System.out.println("Array size = "+ N+", Offset = "+OFFSET);
			System.out.println("Total memory required = "+ ((3.0 * BytesPerWord) * ( (double) N / 1048576.0)) + " MB." );
			System.out.println("Each test is run "+NTIMES+" times, but only the *best* time for each is used.");

			/* Get initial value for system clock. */

			for (j=0; j<N; j++) {
					a[j] = 1.0;
					b[j] = 2.0;
					c[j] = 0.0;
				}

			System.out.println(HLINE);

			if  ( (quantum = checktick()) >= 1)
				System.out.println("Your clock granularity/precision appears to be " +quantum+ " microseconds.");
			else
				System.out.println("Your clock granularity appears to be less than one microsecond.");

			t = mysecond();
			for (j = 0; j < N; j++)
				a[j] = 2.0E0 * a[j];
			t = 1.0E6 * (mysecond() - t);

			System.out.println("Each test below will take on the order of "+(int) t+" microseconds.");
			System.out.println("   (= "+(int) (t/quantum)+" clock ticks)" );
			System.out.println("Increase the size of the arrays if this shows that you are not getting at least 20 clock ticks per test.");

			System.out.println(HLINE);

			System.out.println("WARNING -- The above is only a rough guideline.");
			System.out.println("For best results, please be sure you know the");
			System.out.println("precision of your system timer.");
			System.out.println(HLINE);

			/*	--- MAIN LOOP --- repeat test cases NTIMES times --- */

			scalar = 3.0;
			for (k=0; k<NTIMES; k++) {

					times[0][k] = mysecond();
					for (j=0; j<N; j++)
						c[j] = a[j];
					times[0][k] = mysecond() - times[0][k];

					times[1][k] = mysecond();
					for (j=0; j<N; j++)
						b[j] = scalar*c[j];
					times[1][k] = mysecond() - times[1][k];

					times[2][k] = mysecond();
					for (j=0; j<N; j++)
						c[j] = a[j]+b[j];
					times[2][k] = mysecond() - times[2][k];

					times[3][k] = mysecond();
					for (j=0; j<N; j++)
						a[j] = b[j]+scalar*c[j];
					times[3][k] = mysecond() - times[3][k];
				}

			/*	--- SUMMARY --- */

			for (k=1; k<NTIMES; k++) /* note -- skip first iteration */
				{
					for (j=0; j<4; j++) {
							avgtime[j] = avgtime[j] + times[j][k];
							mintime[j] = MIN(mintime[j], times[j][k]);
							maxtime[j] = MAX(maxtime[j], times[j][k]);
						}
				}

			System.out.println("Function      Rate (MB/s)   Avg time     Min time     Max time");
			for (j=0; j<4; j++) {
					avgtime[j] = avgtime[j]/(double)(NTIMES-1);

					System.out.println(""+label[j]+(1.0E-06 * bytes[j]/mintime[j])+ " "+avgtime[j] + " "+ mintime[j]+ " " + maxtime[j]  );
				}
			System.out.println(HLINE);

			/* --- Check Results --- */
			//checkSTREAMresults();
			System.out.println(HLINE);
		}

		public double MIN(double x, double y) {
			if(x<y)
				return x;
			else
				return y;
		}

		public double MAX(double x, double y) {
			if(x>y)
				return x;
			else
				return y;
		}


		public static void main(String args[]) {
			stream s = new stream();

		}


		private int checktick() {
			int		i, minDelta, Delta;
			double	t1, t2;
			double[] timesfound = new double[M];

			/*  Collect a sequence of M unique time values from the system. */

			for (i = 0; i < M; i++) {
					t1 = mysecond();
					while( ((t2=mysecond()) - t1) < 1.0E-6 ) {}
					timesfound[i] = t1 = t2;
				}

			/*
			* Determine the minimum difference between these M values.
			* This result will be our estimate (in microseconds) for the
			* clock granularity.
			*/

			minDelta = 1000000;
			for (i = 1; i < M; i++) {
					Delta = (int)( 1.0E6 * (timesfound[i]-timesfound[i-1]));
					minDelta =(int) MIN(minDelta, MAX(Delta,0));
				}

			return(minDelta);
		}



		/** A gettimeofday routine to give access to the wall
		clock timer on most UNIX-like systems.  */
		private double mysecond() {
			//need to return microseconds not milliseconds -- big big problem!

			return System.currentTimeMillis()*1000;
		}

	}

