/// <summary>
        /// This is faster for longer span
        /// </summary>
        /// <param name="data"></param>
        /// <param name="average"></param>
        /// <param name="periodic"></param>
        /// <param name="variance"></param>
        /// <returns></returns>
        public static double Next(double[] data, ref double average, ref List <double> periodic, ref double variance)
        {
            double[] PDR = MonteCarloSimulation.PeriodicChange(data, ref periodic);
            average  = AMath.Average(PDR, average);
            variance = AMath.Variance(PDR, average, variance, false);
            double Drift             = average - (variance / 2.0);
            double StandardDeviation = Math.Sqrt(variance); //AMath.StandarDeviation(Variance);

            return(data.Last() * Math.Exp(Drift + StandardDeviation * AExcel.NORMSINV(AMath.Random())));
        }
        /// <summary>
        /// this is faster for short span
        /// Simulates next value of double set
        /// </summary>
        /// <param name="data"></param>
        /// <returns>future random output</returns>
        public static double Next(double[] data)
        {
            if (data == null || data.Length <= 0)
            {
                return(double.NaN);
            }

            double[] PFR               = MonteCarloSimulation.PeriodicChange(data);
            double   Averange          = AMath.Average(PFR);
            double   Variance          = AMath.Variance(PFR, Averange, false);
            double   Drift             = Averange - (Variance / 2.0);
            double   StandardDeviation = Math.Sqrt(Variance); //AMath.StandarDeviation(Variance);

            return(data.Last() * Math.Exp(Drift + StandardDeviation * AExcel.NORMSINV(AMath.Random())));
        }
        public static double[] PeriodicChange(double[] data, ref List <double> last)
        {
            int length = data.Length;

            double[] output = new double[length - 1];

            if (last.Count == 0)
            {
                output = MonteCarloSimulation.PeriodicChange(data);
            }
            else
            {
                int LN1 = data.Length - 1;
                last.Add(Math.Log(data[LN1] / data[LN1 - 1]));
                output = last.ToArray();
            }


            return(output);
        }
        /// <summary>
        /// Simulates N next values
        /// </summary>
        /// <param name="data"></param>
        /// <param name="N">count of values in generated sequence</param>
        /// <returns></returns>
        public static List <double> Next(double[] data, int N)
        {
            if (data == null || data.Length <= 0)
            {
                return(null);
            }

            List <double> input = data.ToList();

            double[]      output   = new double[N];
            double        average  = double.NaN;
            double        variance = double.NaN;
            List <double> periodic = new List <double>();

            int i = 0;

            for (; i < N; i++)
            {
                output[i] = MonteCarloSimulation.Next(input.ToArray(), ref average, ref periodic, ref variance);
                input.Add(output[i]);
            }

            return(output.ToList());
        }