C#,码海拾贝(06)——连分式(Continued Fraction)曲线插值算法,《C#数值计算算法编程》源代码升级改进版

一、连分式法

连分式法是一种有理函数逼近法,其基本出发点是:将原型展开成连分式,然后截取前面几个起主要作用的偏系数构成简化模型,连分式法计算简便,拟合精度较高,是一种很有效的传递函数简化法。

Continued Fraction

In mathematicsa continued fraction is an expression obtained through an iterative process of representing a number as the sum of its integer part and the reciprocal of another numberthen writing this other number as the sum of its integer part and another reciprocaland so onIn a finite continued fraction (or terminated continued fraction), the iteration/recursion is terminated after finitely many steps by using an integer in lieu of another continued fraction.

在数学中,连分式是通过迭代过程获得的表达式,将一个数表示为其整数部分和另一个数的倒数的和,然后将该另一个数字写成其整数部分与另一个倒数的和,在有限的连续分数(或终止的连续分数)中,通过使用整数代替另一个连续分数,在有限多个步骤之后终止迭代/递归。

Continued fractions have been studied for over two thousand years, with one of the first recorded studies being that of Euclid around 300 BC (in his book Elements) when he used them to find the greatest common divisor of two integers (using what is known today as the Euclidean algorithm).

Since then, continued fractions have shown up in a variety of other areas, including, but not limited to,

rational approximations for real numbers
solving linear Diophantine equations
solving Pell's equation
approximating PI
 

连分式已经被研究了两千多年,最早有记录的研究之一是公元前300年左右的欧几里得(在他的《元素》一书中),当时他用它们来寻找两个整数的最大公约数(使用今天所说的欧几里得算法)。

从那时起,连分式已经出现在各种其他领域,包括但不限于,

  • 实数的有理逼近
  • 求解线性丢番图方程
  • 求解佩尔方程
  • 近似PI

二、改进代码

using System;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;

namespace Zhou.CSharp.Algorithm
{
    /// <summary>
    /// 插值计算类Interpolation.cs
    /// 作者:周长发
    /// 改编:深度混淆
    /// https://blog.csdn.net/beijinghorn
    /// </summary>
    public static partial class Interpolation
    {
        /// <summary>
        /// 连分式不等距插值
        /// </summary>
        /// <param name="x">一维数组,长度为n,存放给定的n个结点的值x(i),要求x(0)<x(1)<...<x(n-1)</param>
        /// <param name="y">一维数组,长度为n,存放给定的n个结点的函数值y(i),y(i) = f(x(i)), i=0,1,...,n-1</param>
        /// <param name="t">存放指定的插值点的x值</param>
        /// <returns>指定的查指点t的函数近似值y=f(t)</returns>
        public static double Continued_Fraction(double[] x, double[] y, double t)
        {
            int n = x.Length;
            double z = 0.0;

            // 特例处理
            if (n < 1)
            {
                return (z);
            }
            else if (n == 1)
            {
                z = y[0];
                return (z);
            }

            // 连分式插值
            int k = 0;
            int m = 0;
            if (n <= 8)
            {
                k = 0;
                m = n;
            }
            else if (t < x[4])
            {
                k = 0;
                m = 8;
            }
            else if (t > x[n - 5])
            {
                k = n - 8;
                m = 8;
            }
            else
            {
                k = 1;
                int j = n;

                while (j - k != 1)
                {
                    int i = (k + j) / 2;
                    if (t < x[i - 1])
                    {
                        j = i;
                    }
                    else
                    {
                        k = i;
                    }
                }
                k = k - 4;
                m = 8;
            }

            double[] b = new double[8];
            b[0] = y[k];
            for (int i = 2; i <= m; i++)
            {
                double h = y[i + k - 1];
                int w = 0;
                int j = 1;
                while ((w == 0) && (j <= i - 1))
                {
                    if (Math.Abs(h - b[j - 1]) < float.Epsilon)
                    {
                        w = 1;
                    }
                    else
                    {
                        h = (x[i + k - 1] - x[j + k - 1]) / (h - b[j - 1]);
                    }
                    j = j + 1;
                }

                b[i - 1] = h;

                if (w != 0)
                {
                    b[i - 1] = float.MaxValue;//  1.0e+35;
                }
            }

            z = b[m - 1];
            for (int i = m - 1; i >= 1; i--)
            {
                z = b[i - 1] + (t - x[i + k - 1]) / z;
            }
            return (z);
        }

        /// <summary>
        /// 连分式等距插值
        /// (使用非等距插值的方法)
        /// </summary>
        /// <param name="x0">存放等距n个结点中第一个结点的值</param>
        /// <param name="step">等距结点的步长</param>
        /// <param name="y">一维数组,长度为n,存放给定的n个结点的函数值y(i),y(i) = f(x(i)), i=0,1,...,n-1</param>
        /// <param name="t">存放指定的插值点的x值</param>
        /// <returns>指定的查指点t的函数近似值y=f(t)</returns>
        public static double Continued_Fraction(double x0, double step, double[] y, double t)
        {
            double[] x = new double[y.Length];
            for (int i = 0; i < y.Length; i++, x0 += step)
            {
                x[i] = x0;
            }
            return Continued_Fraction(x, y, t);
        }
#if __OLD__
        /// <summary>
        /// 连分式等距插值
        /// </summary>
        /// <param name="x0">存放等距n个结点中第一个结点的值</param>
        /// <param name="step">等距结点的步长</param>
        /// <param name="y">一维数组,长度为n,存放给定的n个结点的函数值y(i),y(i) = f(x(i)), i=0,1,...,n-1</param>
        /// <param name="t">存放指定的插值点的x值</param>
        /// <returns>指定的查指点t的函数近似值y=f(t)</returns>
        public static double Continued_Fraction(double x0, double step, double[] y, double t)
        {
            int n = y.Length;
            double z = 0.0;

            // 特例处理
            if (n < 1)
            {
                return (z);
            }
            else if (n == 1)
            {
                z = y[0];
                return (z);
            }

            // 连分式插值
            int k = 0;
            int m = 0;
            if (n <= 8)
            {
                k = 0;
                m = n;
            }
            else if (t < (x0 + 4.0 * step))
            {
                k = 0;
                m = 8;
            }
            else if (t > (x0 + (n - 5) * step))
            {
                k = n - 8;
                m = 8;
            }
            else
            {
                k = (int)((t - x0) / step) - 3;
                m = 8;
            }

            double[] b = new double[8];
            b[0] = y[k];
            for (int i = 2; i <= m; i++)
            {
                double hh = y[i + k - 1];
                int l = 0;
                int j = 1;

                while ((l == 0) && (j <= i - 1))
                {
                    if (Math.Abs(hh - b[j - 1]) + 1.0 == 1.0)
                    {
                        l = 1;
                    }
                    else
                    {
                        double xi = x0 + (i + k - 1) * step;
                        double xj = x0 + (j + k - 1) * step;
                        hh = (xi - xj) / (hh - b[j - 1]);
                    }

                    j = j + 1;
                }

                b[i - 1] = hh;
                if (l != 0)
                {
                    b[i - 1] = float.MaxValue;// 1.0e+35;
                }
            }

            z = b[m - 1];
            for (int i = m - 1; i >= 1; i--)
            {
                z = b[i - 1] + (t - (x0 + (i + k - 1) * step)) / z;
            }
            return (z);
        }
#endif
    }
}

POWER BY 315SOFT.COM

基于坐标点的计算,从点集计算插值曲线等拓展方法请参阅《拉格朗日插值算法及其拓展

猜你喜欢

转载自blog.csdn.net/beijinghorn/article/details/129828898