微軟公司內部培訓程序員資料---計算數值積分的類

/*
 * 計算數值積分的類 Integral
 * 
 * 周長發編制
 */

using System;

namespace MSAlgorithm
{
    public abstract class Integral
    {
        /// <summary>
        /// 抽象函數:計算積分函數值,必須在派生類中覆蓋該函數
        /// </summary>
        /// <param name="x">函數變量</param>
        /// <returns>double型,對應的函數值</returns>
        public abstract double Func(double x);

        /// <summary>
        /// 基本構造函數
        /// </summary>
        public Integral()
        { }

        /// <summary>
        /// 變步長梯形求積法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <param name="a">積分下限</param>
        /// <param name="b">積分上限,要求b>a</param>
        /// <param name="eps">積分精度要求</param>
        /// <returns>double 型,積分值</returns>
        public double GetValueTrapezia(double a, double b, double eps)
        {
            int n, k;
            double fa, fb, h, t1, p, s, x, t = 0;

            //積分區間端點的函數值
            fa = Func(a);
            fb = Func(b);

            //迭代初值
            n = 1;
            h = b - a;
            t1 = h * (fa + fb) / 2.0;
            p = eps + 1.0;

            //迭代計算
            while (p >= eps)
            {
                s = 0.0;
                for (k = 0; k <= n - 1; k++)
                {
                    x = a + (k + 0.5) * h;
                    s = s + Func(x);
                }

                t = (t1 + h * s) / 2.0;
                p = Math.Abs(t1 - t);
                t1 = t;
                n = n + n;
                h = h / 2.0;
            }

            return (t);
        }

        /// <summary>
        /// 變步長辛卜生求積法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <param name="a">積分下限</param>
        /// <param name="b">積分上限,要求b>a</param>
        /// <param name="eps">積分精度要求</param>
        /// <returns>double 型,積分值</returns>
        public double GetValueSimpson(double a, double b, double eps)
        {
            int n, k;
            double h, t1, t2, s1, s2 = 0, ep, p, x;

            //計算初值
            n = 1;
            h = b - a;
            t1 = h * (Func(a) + Func(b)) / 2.0;
            s1 = t1;
            ep = eps + 1.0;

            //迭代計算
            while (ep >= eps)
            {
                p = 0.0;
                for (k = 0; k <= n - 1; k++)
                {
                    x = a + (k + 0.5) * h;
                    p = p + Func(x);
                }

                t2 = (t1 + h * p) / 2.0;
                s2 = (4.0 * t2 - t1) / 3.0;
                ep = Math.Abs(s2 - s1);
                t1 = t2;
                s1 = s2;
                n = n + n;
                h = h / 2.0;
            }

            return (s2);
        }

        /// <summary>
        /// 自適應梯形求積法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <param name="a">積分下限</param>
        /// <param name="b">積分上限,要求b>a</param>
        /// <param name="d">對積分區間進行分割的最小步長,當子區間的寬度,小於d時,即使沒有滿足精度要求,也不再往下進行分割</param>
        /// <param name="eps">積分精度要求</param>
        /// <returns>double 型,積分值</returns>
        public double GetValueATrapezia(double a, double b, double d, double eps)
        {
            double h, f0, f1, t0, z;
            double[] t = new double[2];

            //迭代初值
            h = b - a;
            t[0] = 0.0;
            f0 = Func(a);
            f1 = Func(b);
            t0 = h * (f0 + f1) / 2.0;

            //遞歸計算
            ppp(a, b, h, f0, f1, t0, eps, d, t);

            z = t[0];

            return (z);
        }

        /// <summary>
        /// 內部函數
        /// </summary>
        /// <param name="x0"></param>
        /// <param name="x1"></param>
        /// <param name="h"></param>
        /// <param name="f0"></param>
        /// <param name="f1"></param>
        /// <param name="t0"></param>
        /// <param name="eps"></param>
        /// <param name="d"></param>
        /// <param name="t"></param>
        private void ppp(double x0, double x1, double h, double f0, double f1, double t0, double eps, double d, double[] t)
        {
            double x, f, t1, t2, p, g, eps1;

            x = x0 + h / 2.0;
            f = Func(x);
            t1 = h * (f0 + f) / 4.0;
            t2 = h * (f + f1) / 4.0;
            p = Math.Abs(t0 - (t1 + t2));

            if ((p < eps) || (h / 2.0 < d))
            {
                t[0] = t[0] + (t1 + t2);
                return;
            }
            else
            {
                g = h / 2.0;
                eps1 = eps / 1.4;
                //遞歸
                ppp(x0, x, g, f0, f, t1, eps1, d, t);
                ppp(x, x1, g, f, f1, t2, eps1, d, t);
                return;
            }
        }

        /// <summary>
        /// 龍貝格求積法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <param name="a">積分下限</param>
        /// <param name="b">積分上限,要求b>a</param>
        /// <param name="eps">積分精度要求</param>
        /// <returns>double 型,積分值</returns>
        public double GetValueRomberg(double a, double b, double eps)
        {
            int m, n, i, k;
            double h, ep, p, x, s, q = 0;
            double[] y = new double[10];

            //迭代初值
            h = b - a;
            y[0] = h * (Func(a) + Func(b)) / 2.0;
            m = 1;
            n = 1;
            ep = eps + 1.0;

            //迭代計算
            while ((ep >= eps) && (m <= 9))
            {
                p = 0.0;
                for (i = 0; i < n - 1; i++)
                {
                    x = a + (i + 0.5) * h;
                    p = p + Func(x);
                }

                p = (y[0] + h * p) / 2.0;
                s = 1.0;
                for (k = 1; k <= m; k++)
                {
                    s = 4.0 * s;
                    q = (s * p - y[k - 1]) / (s - 1.0);
                    y[k - 1] = p;
                    p = q;
                }

                ep = Math.Abs(q - y[m - 1]);
                m = m + 1;
                y[m - 1] = q;
                n = n + n;
                h = h / 2.0;
            }

            return (q);
        }

        /// <summary>
        /// 計算一維積分的連分式法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <param name="a">積分下限</param>
        /// <param name="b">積分上限,要求b>a</param>
        /// <param name="eps">積分精度要求</param>
        /// <returns>double 型,積分值</returns>
        public double GetValuePq(double a, double b, double eps)
        {
            int m, n, k, l, j;
            double hh, t1, s1, ep, s, x, t2, g = 0;
            double[] h = new double[10];
            double[] bb = new double[10];

            //迭代初值
            m = 1;
            n = 1;
            hh = b - a;
            h[0] = hh;
            t1 = hh * (Func(a) + Func(b)) / 2.0;
            s1 = t1;
            bb[0] = s1;
            ep = 1.0 + eps;

            //迭代計算
            while ((ep >= eps) && (m <= 9))
            {
                s = 0.0;
                for (k = 0; k <= n - 1; k++)
                {
                    x = a + (k + 0.5) * hh;
                    s = s + Func(x);
                }

                t2 = (t1 + hh * s) / 2.0;
                m = m + 1;
                h[m - 1] = h[m - 2] / 2.0;
                g = t2;
                l = 0;
                j = 2;

                while ((l == 0) && (j <= m))
                {
                    s = g - bb[j - 2];
                    if (Math.Abs(s) + 1.0 == 1.0)
                        l = 1;
                    else
                        g = (h[m - 1] - h[j - 2]) / s;

                    j = j + 1;
                }

                bb[m - 1] = g;
                if (l != 0)
                    bb[m - 1] = 1.0e+35;

                g = bb[m - 1];
                for (j = m; j >= 2; j--)
                    g = bb[j - 2] - h[j - 2] / g;

                ep = Math.Abs(g - s1);
                s1 = g;
                t1 = t2;
                hh = hh / 2.0;
                n = n + n;
            }

            return (g);
        }

        /// <summary>
        /// 高振盪函數求積法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <param name="a">積分下限</param>
        /// <param name="b">積分上限,要求b>a</param>
        /// <param name="m">被積函數中振盪函數的角頻率</param>
        /// <param name="n">給定積分區間兩端點上的導數最高階數+1</param>
        /// <param name="fa">一維數組,長度爲n,存放f(x)在積分區間端點x=a處的各階導數值<param>
        /// <param name="fb">一維數組,長度爲n,存放f(x)在積分區間端點x=b處的各階導數值</param>
        /// <param name="s">一維數組,長度爲2,其中s(1)返回f(x)cos(mx)在積分區間的積分值,
        ///  s(2) 返回f(x)sin(mx)在積分區間的積分值</param>
        /// <returns>double 型,積分值</returns>
        public double GetValuePart(double a, double b, int m, int n, double[] fa, double[] fb, double[] s)
        {
            int mm, k, j;
            double sma, smb, cma, cmb;
            double[] sa = new double[4];
            double[] sb = new double[4];
            double[] ca = new double[4];
            double[] cb = new double[4];

            //三角函數值
            sma = Math.Sin(m * a);
            smb = Math.Sin(m * b);
            cma = Math.Cos(m * a);
            cmb = Math.Cos(m * b);

            //迭代初值
            sa[0] = sma;
            sa[1] = cma;
            sa[2] = -sma;
            sa[3] = -cma;
            sb[0] = smb;
            sb[1] = cmb;
            sb[2] = -smb;
            sb[3] = -cmb;
            ca[0] = cma;
            ca[1] = -sma;
            ca[2] = -cma;
            ca[3] = sma;
            cb[0] = cmb;
            cb[1] = -smb;
            cb[2] = -cmb;
            cb[3] = smb;
            s[0] = 0.0;
            s[1] = 0.0;

            mm = 1;

            //循環迭代
            for (k = 0; k <= n - 1; k++)
            {
                j = k;
                while (j >= 4)
                    j = j - 4;

                mm = mm * m;
                s[0] = s[0] + (fb[k] * sb[j] - fa[k] * sa[j]) / (1.0 * mm);
                s[1] = s[1] + (fb[k] * cb[j] - fa[k] * ca[j]) / (1.0 * mm);
            }

            s[1] = -s[1];

            return s[0];
        }

        /// <summary>
        /// 勒讓德-高斯求積法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <param name="a">積分下限</param>
        /// <param name="b">積分上限,要求b>a</param>
        /// <param name="eps">積分精度要求</param>
        /// <returns>double 型,積分值</returns>
        public double GetValueLegdGauss(double a, double b, double eps)
        {
            int m, i, j;
            double s, p, ep, h, aa, bb, w, x, g = 0;

            //勒讓德-高斯求積係數
            double[] t ={-0.9061798459,-0.5384693101,0.0,
						   0.5384693101,0.9061798459};
            double[] c ={0.2369268851,0.4786286705,0.5688888889,
						   0.4786286705,0.2369268851};

            //迭代初值
            m = 1;
            h = b - a;
            s = Math.Abs(0.001 * h);
            p = 1.0e+35;
            ep = eps + 1.0;

            //迭代計算
            while ((ep >= eps) && (Math.Abs(h) > s))
            {
                g = 0.0;
                for (i = 1; i <= m; i++)
                {
                    aa = a + (i - 1.0) * h;
                    bb = a + i * h;
                    w = 0.0;

                    for (j = 0; j <= 4; j++)
                    {
                        x = ((bb - aa) * t[j] + (bb + aa)) / 2.0;
                        w = w + Func(x) * c[j];
                    }

                    g = g + w;
                }

                g = g * h / 2.0;
                ep = Math.Abs(g - p) / (1.0 + Math.Abs(g));
                p = g;
                m = m + 1;
                h = (b - a) / m;
            }

            return (g);
        }

        /// <summary>
        /// 拉蓋爾-高斯求積法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <returns>double 型,積分值</returns>
        public double GetValueLgreGauss()
        {
            int i;
            double x, g;

            //拉蓋爾-高斯求積係數
            double[] t = { 0.26355990, 1.41340290, 3.59642600, 7.08580990, 12.64080000 };
            double[] c = { 0.6790941054, 1.638487956, 2.769426772, 4.315944000, 7.104896230 };

            //循環計算
            g = 0.0;
            for (i = 0; i <= 4; i++)
            {
                x = t[i];
                g = g + c[i] * Func(x);
            }

            return (g);
        }

        /// <summary>
        /// 埃爾米特-高斯求積法
        /// 調用時,須覆蓋計算函數f(x)值的虛函數double Func(double x)
        /// </summary>
        /// <returns>double 型,積分值</returns>
        public double GetValueHermiteGauss()
        {
            int i;
            double x, g;

            //埃爾米特-高斯求積係數
            double[] t = { -2.02018200, -0.95857190, 0.0, 0.95857190, 2.02018200 };
            double[] c = { 1.181469599, 0.9865791417, 0.9453089237, 0.9865791417, 1.181469599 };

            //循環計算
            g = 0.0;
            for (i = 0; i <= 4; i++)
            {
                x = t[i];
                g = g + c[i] * Func(x);
            }

            return (g);
        }
    }
}


注:本代碼爲原作者所有,本人只是摘錄,如有侵犯作者,請與本人聯繫

Email:[email protected]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章