COSTA: COSt and Termination Analyzer for Java Bytecode
    
    package x10;


//import java.util.Random;


public class CUDABlackScholes {

    static void doBlackScholes(//float optionYears[],
			       //float stockPrice[],
			       //float optionStrike[],
			       //float callResult[],
			       //float putResult[],
			       //float R,
			       //float V,
			       int opt_N
			       ) {
        int blocks = 480;
        int threads = 128;
	Conc.finish_begin();
	doBlackScholes_mainLoop(/*optionYears,stockPrice,optionStrike,callResult,putResult,R,V,*/opt_N,blocks,threads);
	Conc.finish_end();
    }
    
    
    static void doBlackScholes_mainLoop(//float optionYears[],
					//float stockPrice[],
					//float optionStrike[],
					//float callResult[],
					//float putResult[],
					//float R, 
					//float V,
					int opt_N,
					int blocks,
					int threads) {
	Conc.async_begin();
	doBlackScholes_mainLoop_1(/*optionYears,stockPrice,optionStrike,callResult,putResult,R,V,*/opt_N,blocks,threads);
	Conc.async_end();
    }
    
    
    static void doBlackScholes_mainLoop_1(//float optionYears[],
					  //float stockPrice[],
					  //float optionStrike[],
					  //float callResult[],
					  //float putResult[],
					  //float R,
					  //float V,
					  int opt_N,
					  int blocks,
					  int threads) {

	for (int block=0; block<blocks; block++) {
	    for (int thread=0; thread<threads; thread++) {
		Conc.async_begin();
		doBlackScholes_innerLoop(/*optionYears,stockPrice,optionStrike,callResult,putResult,R,V,*/opt_N,blocks,threads,block,thread);
		Conc.async_end();
	    }
	}
    }


    static void doBlackScholes_innerLoop(//float optionYears[],
					 //float stockPrice[],
					 //float optionStrike[],
					 //float callResult[],
					 //float putResult[],
					 //float R,
					 //float V,
					 int opt_N,
					 int blocks,
					 int threads,
					 int block,
					 int thread) {
	//int tid = block * threads + thread;
	//int tids = blocks * threads;
	//for (int opt=tid; opt<opt_N; opt+=tids) {
	    //float A1 = 0.31938153f;
	    //float A2 = -0.356563782f;
	    //float A3 = 1.781477937f;
	    //float A4 = -1.821255978f;
	    //float A5 = 1.330274429f;
	    //float RSQRT2PI = 0.39894228040143267793994605993438f;
	    
	    //float T = optionYears[opt];
	    //float S = stockPrice[opt];
	    //float X = optionStrike[opt];
	    //float sqrtT = (float) Math.sqrt(T);
	    //float d1 = ((float) Math.log(S/X) + (R + 0.5f * V * V) * T) / (V * sqrtT); 
	    //float d2 = d1 - V * sqrtT;
	    
	    //float K1 = 1.0f / (1.0f + 0.2316419f * Math.abs(d1));
	    //float K2 = 1.0f / (1.0f + 0.2316419f * Math.abs(d2));
	    //float CNDD1 = RSQRT2PI * (float) Math.exp(- 0.5f * d1 * d1) * 
	    //	(K1 * (A1 + K1 * (A2 + K1 * (A3 + K1 * (A4 + K1 * A5)))));
	    //float CNDD2 = RSQRT2PI * (float) Math.exp(- 0.5f * d2 * d2) * 
	    //	(K2 * (A1 + K2 * (A2 + K2 * (A3 + K2 * (A4 + K2 * A5)))));
	    
	    //if (d1 > 0) CNDD1 = 1.0f - CNDD1;
	    //if (d2 > 0) CNDD2 = 1.0f - CNDD2;
	    
	    //float expRT = (float) Math.exp(- R * T); 
	    //callResult[opt] = S * CNDD1 - X * expRT * CNDD2;
	    //putResult[opt]  = X * expRT * (1.0f - CNDD2) - S * (1.0f - CNDD1); 
	//}
    }


    public static void main(String args[]) {

        // Problem parameters
        int OPT_N = 4000000;
        int NUM_ITERATIONS = args.length;//512;
        //float RISKFREE = 0.02f;
        //float VOLATILITY = 0.30f;

        //Random rand = new Random();

        //float h_CallResultCPU[] = {};
        //float h_PutResultCPU[] = {};
        //float h_CallResultGPU[] = {};
        //float h_PutResultGPU[] = {};
        //float h_StockPrice[] = {};
        //float h_OptionStrike[] = {};
        //float h_OptionYears[] = {};

        //float d_CallResult[] = {};
        //float d_PutResult[] = {};
        //float d_StockPrice[] = {};
        //float d_OptionStrike[] = {};
        //float d_OptionYears[] = {};

	// array initializing (is OPT_N the length?)
	//for(int i=0; i<OPT_N; i++) {
	//    h_CallResultCPU[i] = 0;
	//    h_PutResultCPU[i] = -1;
	//    h_CallResultGPU[i] = 0;
	//    h_PutResultGPU[i] = 0;
	//    h_StockPrice[i] = rand.nextFloat();
	//    h_OptionStrike[i] = rand.nextFloat();
	//    h_OptionYears[i] = rand.nextFloat();

	//    d_CallResult[i] = 0;
	//    d_PutResult[i] = 0;
	//    d_StockPrice[i] = h_StockPrice[i];
	//    d_OptionStrike[i] = h_OptionStrike[i];
	//    d_OptionYears[i] = h_OptionYears[i];
	//}

        for (int i=0; i<NUM_ITERATIONS; i++) {
            doBlackScholes(/*d_OptionYears,d_StockPrice,d_OptionStrike,d_CallResult,d_PutResult,RISKFREE,VOLATILITY*/OPT_N);
        }

	// here, for simplicity, two calls in a finish have been replaced by two finish calls
	Conc.finish_begin();
	copyArray(/*d_CallResult,h_CallResultGPU,*/0,OPT_N);
	Conc.finish_end();
	Conc.finish_begin();
	copyArray(/*d_PutResult,h_PutResultGPU,*/0,OPT_N);
	Conc.finish_end();

        doBlackScholes(/*h_OptionYears,h_StockPrice,h_OptionStrike,h_CallResultCPU,h_PutResultCPU,RISKFREE,VOLATILITY*/OPT_N);
        //float sum_delta = 0.0f;
        //float sum_ref = 0.0f;
        //float max_delta = 0.0f;
        //for (int i=0; i<OPT_N; i++) {
	//float ref_val = h_CallResultCPU[i];
        //    float delta = Math.abs(ref_val - h_CallResultGPU[i]);
        //    if (delta > max_delta) max_delta = delta;
        //    sum_delta += delta;
        //    sum_ref   += Math.abs(ref_val);
        //}
        //float L1norm = sum_delta / sum_ref;
    }


    public static void copyArray(//float source[],
				 //float target[],
				 int from,
				 int to) {
	//for (int i=from; i<to; i++) target[i] = source[i];
    }



}