C#,数值计算——函数计算,切比雪夫近似算法(Chebyshev approximation)的计算方法与源程序

1 文本格式

using System;

namespace Legalsoft.Truffer

{

/// <summary>

/// Chebyshev approximation

/// </summary>

public class Chebyshev

{

private int n { get; set; }

private int m { get; set; }

private double\[\] c { get; set; }

private double a { get; set; }

private double b { get; set; }

public Chebyshev(double\[\] cc, double aa, double bb)

{

this.n = cc.Length;

this.m = n;

this.c = Globals.CopyFrom(cc);

this.a = aa;

this.b = bb;

}

public Chebyshev(double\[\] d)

{

this.n = d.Length;

this.m = n;

this.c = new doublen;

this.a = -1.0;

this.b = 1.0;

cn - 1 = dn - 1;

cn - 2 = 2.0 * dn - 2;

for (int j = n - 3; j >= 0; j--)

{

cj = 2.0 * dj + cj + 2;

for (int i = j + 1; i < n - 2; i++)

{

ci = (ci + ci + 2) / 2;

}

cn - 2 /= 2;

cn - 1 /= 2;

}

}

/*

public Chebyshev(UniVarRealValueFun func, double aa, double bb)

{

new this(func, aa, bb, 50);

}

*/

/// <summary>

/// Inverse of routine polycofs in Chebyshev: Given an array of polynomial

/// coefficients d0..n - 1, construct an equivalent Chebyshev object.

/// </summary>

/// <param name="func"></param>

/// <param name="aa"></param>

/// <param name="bb"></param>

/// <param name="nn"></param>

public Chebyshev(UniVarRealValueFun func, double aa, double bb, int nn = 50)

{

this.n = nn;

this.m = nn;

this.c = new doublen;

this.a = aa;

this.b = bb;

double\[\] f = new doublen;

double bma = 0.5 * (b - a);

double bpa = 0.5 * (b + a);

for (int k = 0; k < n; k++)

{

double y = Math.Cos(Math.PI * (k + 0.5) / n);

fk = func.funk(y * bma + bpa);

}

double fac = 2.0 / n;

for (int j = 0; j < n; j++)

{

double sum = 0.0;

for (int k = 0; k < n; k++)

{

sum += fk * Math.Cos(Math.PI * j * (k + 0.5) / n);

}

cj = fac * sum;

}

}

public double eval(double x, int m)

{

double d = 0.0;

double dd = 0.0;

if ((x - a) * (x - b) > 0.0)

{

throw new Exception("x not in range in Chebyshev::eval");

}

double y = (2.0 * x - a - b) / (b - a);

double y2 = 2.0 * (y);

for (int j = m - 1; j > 0; j--)

{

double sv = d;

d = y2 * d - dd + cj;

dd = sv;

}

return y * d - dd + 0.5 * c0;

}

public double\[\] getc()

{

return c;

}

/// <summary>

/// Return a new Chebyshev object that approximates the derivative of the

/// existing function over the same rangea, b.

/// </summary>

/// <returns></returns>

public Chebyshev derivative()

{

double\[\] cder = new doublen;

cdern - 1 = 0.0;

cdern - 2 = 2 * (n - 1) * cn - 1;

for (int j = n - 2; j > 0; j--)

{

cderj - 1 = cderj + 1 + 2 * j * cj;

}

double con = 2.0 / (b - a);

for (int j = 0; j < n; j++)

{

cderj *= con;

}

return new Chebyshev(cder, a, b);

}

/// <summary>

/// Return a new Chebyshev object that approximates the indefinite integral of

/// the existing function over the same rangea, b. The constant of

/// integration is set so that the integral vanishes at a.

/// </summary>

/// <returns></returns>

public Chebyshev integral()

{

double sum = 0.0;

double fac = 1.0;

double\[\] cint = new doublen;

double con = 0.25 * (b - a);

for (int j = 1; j < n - 1; j++)

{

cintj = con * (cj - 1 - cj + 1) / j;

sum += fac * cintj;

fac = -fac;

}

cintn - 1 = con * cn - 2 / (n - 1);

sum += fac * cintn - 1;

cint0 = 2.0 * sum;

return new Chebyshev(cint, a, b);

}

/// <summary>

/// Polynomial coefficients from a Chebyshev fit.Given a coefficient array

/// c0..n-1, this routine returns a coefficient array d0..n-1 such that

/// sum(k= 0, n-1)dky^k = sum(k= 0, n-1)Tk(y)-c0/2. The method is Clenshaw's

/// recurrence(5.8.11), but now applied algebraically rather than arithmetically.

/// </summary>

/// <param name="m"></param>

/// <returns></returns>

public double\[\] polycofs(int m)

{

double\[\] d = new doublem;

double\[\] dd = new doublem;

for (int j = 0; j < m; j++)

{

dj = 0.0;

ddj = 0.0;

}

d0 = cm - 1;

for (int j = m - 2; j > 0; j--)

{

for (int k = m - j; k > 0; k--)

{

double s1v = dk;

dk = 2.0 * dk - 1 - ddk;

ddk = s1v;

}

double s2v = d0;

d0 = -dd0 + cj;

dd0 = s2v;

}

for (int j = m - 1; j > 0; j--)

{

dj = dj - 1 - ddj;

}

d0 = -dd0 + 0.5 * c0;

return d;

}

public int setm(double thresh)

{

while (m > 1 && Math.Abs(cm - 1) < thresh)

{

m--;

}

return m;

}

public double get(double x)

{

return eval(x, m);

}

public double\[\] polycofs()

{

return polycofs(m);

}

public static void pcshft(double a, double b, double\[\] d)

{

int n = d.Length;

double cnst = 2.0 / (b - a);

double fac = cnst;

for (int j = 1; j < n; j++)

{

dj *= fac;

fac *= cnst;

}

cnst = 0.5 * (a + b);

for (int j = 0; j <= n - 2; j++)

{

for (int k = n - 2; k >= j; k--)

{

dk -= cnst * dk + 1;

}

}

}

public static void ipcshft(double a, double b, double\[\] d)

{

pcshft(-(2.0 + b + a) / (b - a), (2.0 - b - a) / (b - a), d);

}

}

}

2 代码格式

cs 复制代码
using System;

namespace Legalsoft.Truffer
{
    /// <summary>
    /// Chebyshev approximation
    /// </summary>
    public class Chebyshev
    {
        private int n { get; set; }
        private int m { get; set; }
        private double[] c { get; set; }
        private double a { get; set; }
        private double b { get; set; }

        public Chebyshev(double[] cc, double aa, double bb)
        {
            this.n = cc.Length;
            this.m = n;
            this.c = Globals.CopyFrom(cc);
            this.a = aa;
            this.b = bb;
        }

        public Chebyshev(double[] d)
        {
            this.n = d.Length;
            this.m = n;
            this.c = new double[n];
            this.a = -1.0;
            this.b = 1.0;

            c[n - 1] = d[n - 1];
            c[n - 2] = 2.0 * d[n - 2];
            for (int j = n - 3; j >= 0; j--)
            {
                c[j] = 2.0 * d[j] + c[j + 2];
                for (int i = j + 1; i < n - 2; i++)
                {
                    c[i] = (c[i] + c[i + 2]) / 2;
                }
                c[n - 2] /= 2;
                c[n - 1] /= 2;
            }
        }
        /*
        public Chebyshev(UniVarRealValueFun func, double aa, double bb)
        {
            new this(func, aa, bb, 50);
        }
        */
        /// <summary>
        /// Inverse of routine polycofs in Chebyshev: Given an array of polynomial
        /// coefficients d[0..n - 1], construct an equivalent Chebyshev object.
        /// </summary>
        /// <param name="func"></param>
        /// <param name="aa"></param>
        /// <param name="bb"></param>
        /// <param name="nn"></param>
        public Chebyshev(UniVarRealValueFun func, double aa, double bb, int nn = 50)
        {
            this.n = nn;
            this.m = nn;
            this.c = new double[n];
            this.a = aa;
            this.b = bb;

            double[] f = new double[n];
            double bma = 0.5 * (b - a);
            double bpa = 0.5 * (b + a);
            for (int k = 0; k < n; k++)
            {
                double y = Math.Cos(Math.PI * (k + 0.5) / n);
                f[k] = func.funk(y * bma + bpa);
            }
            double fac = 2.0 / n;
            for (int j = 0; j < n; j++)
            {
                double sum = 0.0;
                for (int k = 0; k < n; k++)
                {
                    sum += f[k] * Math.Cos(Math.PI * j * (k + 0.5) / n);
                }
                c[j] = fac * sum;
            }
        }

        public double eval(double x, int m)
        {
            double d = 0.0;
            double dd = 0.0;

            if ((x - a) * (x - b) > 0.0)
            {
                throw new Exception("x not in range in Chebyshev::eval");
            }
            double y = (2.0 * x - a - b) / (b - a);
            double y2 = 2.0 * (y);
            for (int j = m - 1; j > 0; j--)
            {
                double sv = d;
                d = y2 * d - dd + c[j];
                dd = sv;
            }
            return y * d - dd + 0.5 * c[0];
        }

        public double[] getc()
        {
            return c;
        }

        /// <summary>
        /// Return a new Chebyshev object that approximates the derivative of the
        /// existing function over the same range[a, b].
        /// </summary>
        /// <returns></returns>
        public Chebyshev derivative()
        {
            double[] cder = new double[n];
            cder[n - 1] = 0.0;
            cder[n - 2] = 2 * (n - 1) * c[n - 1];
            for (int j = n - 2; j > 0; j--)
            {
                cder[j - 1] = cder[j + 1] + 2 * j * c[j];
            }
            double con = 2.0 / (b - a);
            for (int j = 0; j < n; j++)
            {
                cder[j] *= con;
            }
            return new Chebyshev(cder, a, b);
        }

        /// <summary>
        /// Return a new Chebyshev object that approximates the indefinite integral of
        /// the existing function over the same range[a, b]. The constant of
        /// integration is set so that the integral vanishes at a.
        /// </summary>
        /// <returns></returns>
        public Chebyshev integral()
        {
            double sum = 0.0;
            double fac = 1.0;
            double[] cint = new double[n];
            double con = 0.25 * (b - a);
            for (int j = 1; j < n - 1; j++)
            {
                cint[j] = con * (c[j - 1] - c[j + 1]) / j;
                sum += fac * cint[j];
                fac = -fac;
            }
            cint[n - 1] = con * c[n - 2] / (n - 1);
            sum += fac * cint[n - 1];
            cint[0] = 2.0 * sum;
            return new Chebyshev(cint, a, b);
        }

        /// <summary>
        /// Polynomial coefficients from a Chebyshev fit.Given a coefficient array
        /// c[0..n-1], this routine returns a coefficient array d[0..n-1] such that
        /// sum(k= 0, n-1)dky^k = sum(k= 0, n-1)Tk(y)-c0/2. The method is Clenshaw's
        /// recurrence(5.8.11), but now applied algebraically rather than arithmetically.
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        public double[] polycofs(int m)
        {
            double[] d = new double[m];
            double[] dd = new double[m];
            for (int j = 0; j < m; j++)
            {
                d[j] = 0.0;
                dd[j] = 0.0;
            }
            d[0] = c[m - 1];
            for (int j = m - 2; j > 0; j--)
            {
                for (int k = m - j; k > 0; k--)
                {
                    double s1v = d[k];
                    d[k] = 2.0 * d[k - 1] - dd[k];
                    dd[k] = s1v;
                }
                double s2v = d[0];
                d[0] = -dd[0] + c[j];
                dd[0] = s2v;
            }
            for (int j = m - 1; j > 0; j--)
            {
                d[j] = d[j - 1] - dd[j];
            }
            d[0] = -dd[0] + 0.5 * c[0];
            return d;
        }

        public int setm(double thresh)
        {
            while (m > 1 && Math.Abs(c[m - 1]) < thresh)
            {
                m--;
            }
            return m;
        }

        public double get(double x)
        {
            return eval(x, m);
        }

        public double[] polycofs()
        {
            return polycofs(m);
        }

        public static void pcshft(double a, double b, double[] d)
        {
            int n = d.Length;
            double cnst = 2.0 / (b - a);
            double fac = cnst;
            for (int j = 1; j < n; j++)
            {
                d[j] *= fac;
                fac *= cnst;
            }
            cnst = 0.5 * (a + b);
            for (int j = 0; j <= n - 2; j++)
            {
                for (int k = n - 2; k >= j; k--)
                {
                    d[k] -= cnst * d[k + 1];
                }
            }
        }

        public static void ipcshft(double a, double b, double[] d)
        {
            pcshft(-(2.0 + b + a) / (b - a), (2.0 - b - a) / (b - a),  d);
        }

    }
}
相关推荐
hez20102 小时前
在 .NET 上构建超大托管数组
c#·.net·.net core·gc·clr
先吃饱再说6 小时前
判断回文字符串,从一行代码到双指针优化
算法
见过夏天6 小时前
C++ 基础入门完全指南
c++
黄敬峰8 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术10 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六13 小时前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术14 小时前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize14 小时前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考1 天前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习