C#,数值计算——用于从连续的数据值流估计任意分位数的计算方法与源程序

 

using System;

namespace Legalsoft.Truffer
{
    ///


    /// Object for estimating arbitrary quantile values 
    /// from a continuing stream of data values.
    ///

    public class IQagent
    {
        public const int nbuf = 1000;
        private int nq { get; set; }
        private int nt { get; set; }
        private int nd { get; set; }
        private double[] pval { get; set; }
        private double[] dbuf;
        private double[] qile { get; set; }
        private double q0 { get; set; }
        private double qm { get; set; }

        public IQagent()
        {
            this.nq = 251;
            this.nt = 0;
            this.nd = 0;
            this.pval = new double[nq];
            this.dbuf = new double[nbuf];
            this.qile = new double[nq];
            this.q0 = 1.0e99;
            this.qm = -1.0e99;

            for (int j = 85; j <= 165; j++)
            {
                pval[j] = (j - 75.0) / 100.0;
            }

            // Set general purpose array of p - values ranging from 1.0e-6 to 1~1.0e-6.
            // You can change this if you want.
            for (int j = 84; j >= 0; j--)
            {
                pval[j] = 0.87191909 * pval[j + 1];
                pval[250 - j] = 1.0 - pval[j];
            }
        }

        ///


        /// Assimilate a new value from the stream.
        ///

        ///
        public void add(double datum)
        {
            dbuf[nd++] = datum;
            if (datum < q0)
            {
                q0 = datum;
            }
            if (datum > qm)
            {
                qm = datum;
            }
            if (nd == nbuf)
            {
                update();
            }
        }

        ///


        /// Batch update.
        /// This function is called by add or report and should not be called directly
        /// by the user.
        ///

        public void update()
        {
            int jd = 0;
            int jq = 1;
            double told = 0.0;
            double tnew = 0.0;
            double[] newqile = new double[nq];

            Sorter.sort(dbuf, nd);

            double qold = q0;
            double qnew = q0;
            qile[0] = newqile[0] = q0;
            qile[nq - 1] = newqile[nq - 1] = qm;
            pval[0] = Math.Min(0.5 / (nt + nd), 0.5 * pval[1]);
            pval[nq - 1] = Math.Max(1.0 - 0.5 / (nt + nd), 0.5 * (1.0 + pval[nq - 2]));
            for (int iq = 1; iq < nq - 1; iq++)
            {
                double target = (nt + nd) * pval[iq];
                if (tnew < target)
                {
                    for (; ; )
                    {
                        if (jq < nq && (jd >= nd || qile[jq] < dbuf[jd]))
                        {
                            qnew = qile[jq];
                            tnew = jd + nt * pval[jq++];
                            if (tnew >= target)
                            {
                                break;
                            }
                        }
                        else
                        {
                            qnew = dbuf[jd];
                            tnew = told;
                            if (qile[jq] > qile[jq - 1])
                            {
                                tnew += nt * (pval[jq] - pval[jq - 1]) * (qnew - qold) / (qile[jq] - qile[jq - 1]);
                            }
                            jd++;
                            if (tnew >= target)
                            {
                                break;
                            }
                            told = tnew++;
                            qold = qnew;
                            if (tnew >= target)
                            {
                                break;
                            }
                        }
                        told = tnew;
                        qold = qnew;
                    }
                }
                //if (tnew == told)
                if (Math.Abs(tnew - told) <= float.Epsilon)
                {
                    newqile[iq] = 0.5 * (qold + qnew);
                }
                else
                {
                    newqile[iq] = qold + (qnew - qold) * (target - told) / (tnew - told);
                }
                told = tnew;
                qold = qnew;
            }
            // qile = newqile;
            qile = Globals.CopyFrom(newqile);
            nt += nd;
            nd = 0;
        }

        ///


        /// Return estimated p-quantile for 
        /// the data seen so far. (E.g., p D 0:5 for median.)
        ///

        ///
        ///
        public double report(double p)
        {
            if (nd > 0)
            {
                update();
            }
            int jl = 0;
            int jh = nq - 1;
            int j;
            while (jh - jl > 1)
            {
                j = (jh + jl) >> 1;
                if (p > pval[j])
                {
                    jl = j;
                }
                else
                {
                    jh = j;
                }
            }
            j = jl;
            double q = qile[j] + (qile[j + 1] - qile[j]) * (p - pval[j]) / (pval[j + 1] - pval[j]);
            return Math.Max(qile[0], Math.Min(qile[nq - 1], q));
        }
    }
}
 

你可能感兴趣的:(C#数值计算,Numerical,Recipes,算法,c#,数值计算,开发语言)