/// <summary>
 /// 
 /// </summary>
 /// <param name="option"></param>
 /// <returns></returns>
 float IAsianOptionPricingEngine.CalculatePrice(AsianOptionSingle option)
 {
     return AsianOptionPricingEngineKernels.CalculatePrice(m_simulationCount, option);
 }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="simulationCount"></param>
        /// <param name="option"></param>
        /// <returns></returns>
        internal static float CalculatePrice(int simulationCount, AsianOptionSingle option)
        {
            // Preconditions
            if (simulationCount < 1) { throw new ArgumentOutOfRangeException("simulationCount"); }
            else if (option == null) { throw new ArgumentNullException("option"); }

            // The number of timesteps to simulate.
            int TimestepCount = (int)(option.Tenor / option.dt);

            // The grid size to use when executing the kernel.
            int GridSize = (simulationCount + c_kernelBlockSize - 1) / c_kernelBlockSize;

            // Holds the path values (only used on the device, so no data is transferred to/from the host for this array).
            float[] Paths = new float[simulationCount * TimestepCount];

            // Holds the partial prices computed on the GPU (before they're averaged into the final price).
            float[] PartialResults = new float[GridSize];

            // Set execution grid/block sizes.
            Launcher.SetBlockSize(c_kernelBlockSize);
            Launcher.SetGridSize(GridSize);

            // Generate paths
            var r = option.RiskFreeRate;
            var sigma = option.Volatility;
            var dt = option.dt;
            var numSims = simulationCount;
            GeneratePaths(Paths, r, sigma, dt, numSims, TimestepCount);

            // Compute option value (partial sums, final sum/average value computed on the CPU)
            var spot = option.SpotPrice;
            var strike = option.StrikePrice;
            var type = option.Type;
            ComputeValue(PartialResults, Paths, spot, strike, type, numSims, TimestepCount);

            // Complete the final part of the reduction (convert sum to average)
            float SumPrices = 0f;
            for (int BlockId = 0; BlockId < GridSize; BlockId++)
            {
                SumPrices += PartialResults[BlockId];
            }

            // Compute the average price of the option over the simulated time interval.
            float MeanPrice = SumPrices / simulationCount;

            // Discount the average price to the present time, then return the discounted value.
            return MeanPrice * (float)Math.Exp(-1.0d * option.RiskFreeRate * option.Tenor);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="option"></param>
        /// <returns></returns>
        float IAsianOptionPricingEngine.CalculatePrice(AsianOptionSingle option)
        {
            // The number of timesteps to simulate.
            int TimestepCount = (int)(option.Tenor / option.dt);

            // Holds the path values.
            float[,] Paths = new float[this.m_simulationCount, TimestepCount];

            // Generate paths
            var r = option.RiskFreeRate;
            var sigma = option.Volatility;
            var dt = option.dt;
            var numSims = this.m_simulationCount;
            GeneratePaths(Paths, r, sigma, dt);

            // Compute the average price of the option at the end of the simulated time interval.
            var spot = option.SpotPrice;
            var strike = option.StrikePrice;
            var type = option.Type;
            var MeanPrice = ComputeValue(Paths, spot, strike, type);

            // Discount the average price to the present time, then return the discounted value.
            var DiscountFactor = (float)Math.Exp(-1.0d * option.RiskFreeRate * option.Tenor);
            var DiscountedPrice = MeanPrice * DiscountFactor;
            return DiscountedPrice;
        }