精华内容
下载资源
问答
  • Numpy 多项式函数

    千次阅读 2019-03-22 15:02:39
    多项式函数是变量的整数次冥与系数的乘积之和,形如 f(x)=anxn+an−1xn−1+......+a2x2+a1x1f(x)=a_{n}x^{n}+a_{n-1}x^{n-1}+......+a_{2}x^{2}+a_{1}x^{1}f(x)=an​xn+an−1​xn−1+......+a2​x2+a1​x1 例:f(x)=...

    多项式函数是变量的整数次冥与系数的乘积之和,形如
    f ( x ) = a n x n + a n − 1 x n − 1 + . . . . . . + a 2 x 2 + a 1 x 1 f(x)=a_{n}x^{n}+a_{n-1}x^{n-1}+......+a_{2}x^{2}+a_{1}x^{1} f(x)=anxn+an1xn1+......+a2x2+a1x1

    例: f ( x ) = 3 2 x 2 + 7 1 x 1 + 2 f(x)=3_{2}x^{2}+7_{1}x^{1}+2 f(x)=32x2+71x1+2

    # python
    a = np.array([3,7,2]) 
    p = np.poly1d(a)
    print(p)
    

    numpy.poly1d(x)函数指只有一个变量的的多项式,x的维数即为多项式的最高次数

    ①加减

    p = p + np.poly1d([1,2])
    # p + [1,2]  亦可
    

    输出: 3 2 x 2 + 7 1 x 1 + 2 − 1 x 1 − 2 3_{2}x^{2}+7_{1}x^{1}+2-{1}x^{1}-2 32x2+71x1+21x12


    ②乘除

    a = np.array([3,7,2]) 
    p = np.poly1d(a)
    p/[1,2]
    >>>(poly1d([ 3.,  4.]), poly1d([-2.])) #返回2个多项式除法的结果,分别为商式和余式  
    

    输出:
    3 x + 4
    2


    ③微分与积分
    #p指对象多项式
    p.deriv()     #微分
    f ( x ) = 3 2 x 2 + 7 1 x 1 + 2 f(x)=3_{2}x^{2}+7_{1}x^{1}+2 f(x)=32x2+71x1+2

    a = np.array([3,7,2]) 
    p = np.poly1d(a)
    print(p.deriv())
    

    输出:6x + 7


    p.integ()     #积分        integ(m=1,k= 0)   m是积几次分,k是常系数是多少


    ④开根

    np.roots§

    更多详见:
    nupy官方文档

    展开全文
  • 全域多项式插值的是在整个插值区域内形成一个多项式函数作为插值函数。关于多项式插值的基本知识,见“计算基本理论”。在单项式基插值和牛顿插值形成的表达式中,求该表达式在某一点处的值使用的Horner嵌套算法啊...

    全域多项式插值指的是在整个插值区域内形成一个多项式函数作为插值函数。关于多项式插值的基本知识,见“计算基本理论”。

    在单项式基插值和牛顿插值形成的表达式中,求该表达式在某一点处的值使用的Horner嵌套算法啊,见"Horner嵌套算法"。

    1. 单项式(Monomial)基插值

    1)插值函数基  单项式基插值采用的函数基是最简单的单项式:$$\phi_j(t)=t^{j-1}, j=1,2,...n;\quad f(t)=p_{n-1}(t)=x_1+x_2t+x_3t^2+...x_nt^{n-1}=\sum\limits_{j=1}^nx_jt^{j-1}$$  所要求解的系数即为单项式系数 $x_1,x_2,...x_n$ ,在这里仍然采用1,2,...n的下标记号而不采用和单项式指数对应的0,1,2,...,n-1的下标仅仅是出于和前后讨论一致的需要。

    2)叠加系数

    单项式基插值采用单项式函数基,若有m个离散数据点需要插值,设使用n项单项式基底:

    $$x_1+t_1x_2+t_1^2x_3+...+t_1^{n-1}x_n=y_1\\ x_1+t_2x_2+t_2^2x_3+...+t_2^{n-1}x_n=y_2\\ ......   ......   ......   ......   ......   ......\\ x_1+t_mx_2+t_m^2x_3+...+t_m^{n-1}x_n=y_m$$  系数矩阵为一 $m\times n$ 的矩阵($m\leq n$),范德蒙(Vandermonde)矩阵:

    $$\begin{bmatrix}1&t_1&t_1^2&...&t_1^{n-1}\\1&t_2&t_2^2&...&t_2^{n-1}\\...&...&...&...&...\\1&t_n&t_n^2&...&t_n^{n-1}\end{bmatrix} \begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=\begin{bmatrix}y_1\\y_2\\...\\y_n\end{bmatrix}$$  根据计算基本理论中的讨论,多项式插值的函数基一定线性无关,且只要离散数据点两两不同,所构成的矩阵行也一定线性无关,这保证了矩阵一定行满秩。此时当且仅当m=n时,叠加系数有且仅有一组解。因此,n=插值基底的个数=离散数据点的个数=多项式次数+1。

    3)问题条件和算法复杂度

    生成范德蒙矩阵的复杂度大致在 $O(n^2)$ 量级;由于范德蒙矩阵并没有什么好的性质,既没有稀疏性,也没有对称性,因此只能使用标准的稠密矩阵分解(如LU)来解决,复杂度在 $O(n^3)$ 量级。因此,问题的复杂度在 $O(n^3)$ 量级。

    范德蒙矩阵存在的问题是,当矩阵的维数越来越高的时候,解线性方程组时问题将越来越病态,条件数越来越大;从另一个角度来说,单项式基底本身趋势相近,次数增大时将越来越趋于平行(见下图)。这将造成随着数据点的增加,确定的叠加系数的不确定度越来越大,因此虽然单项式基很简单,进行插值时却往往不用这一方法。如果仍然采用单项式基底,有时也会进行两种可以改善以上问题的操作:平移(shifting)和缩放(scaling),即将 $((t-c)/d)^{j-1}$ 作为基底。常见的平移和缩放将所有数据点通过线性变换转移到区间[-1,1]中,即:$c=(t_1+t_n)/2,d=(t_n-t_1)/2$ 。

    20181006114053046299.png

    4)算法实现

    使用MATLAB实现单项式插值代码如下:

    function [ polyfunc, vecx, condition ] = MonoPI( vect, vecy, shift, scale )

    % 计算单项式型插值多项式系数

    % 输入四个参数:插值点行向量vect,插值点函数值行向量vecy,平移shift,压限scale;

    % 输出两个参数:插值多项式各项系数行向量vecx,矩阵条件数condition;

    % 设置缺省值:若只输入两个参数,则不平移不缩放

    if nargin==2

    shift = 0; scale = 1;

    end

    % 求解系数

    vecsize = size(vect, 2);

    basis = (vect - shift * ones(1, vecsize))/scale; % 确定基底在各个数据点的取值向量basis

    Mat = vander(basis); condition = cond(Mat); % 用vander命令生成basis的范德蒙矩阵并求条件数

    [L, U] = lu(Mat); vecx = (U\(L\vecy.‘)).‘; vecx = fliplr(vecx); % 标准lu分解解矩阵方程

    % 生成句柄函数polyfunc

    syms t;

    monomial = (t - shift)/scale; vecsize = size(vecx, 2); funeval = vecx(vecsize);

    for i = vecsize:-1:2 % 生成函数的算法采用Horner算法提高效率

    funeval = vecx(i - 1) + monomial*funeval;

    end

    polyfunc = matlabFunction(funeval, ‘Vars‘, t);

    end

    比如对于点:$(-2,-27),(0,-1),(1,0)$ 它具有唯一的二次插值多项式:$p_2(t)=-1+5t-4t^2$ 。调用以上代码:

    % 命令行输入

    [polyfunc, vecx, condition] = MonoPI(vect, vecy)

    % 命令行输出

    polyfunc =

    包含以下值的 function_handle:

    @(t)-t.*(t.*4.0-5.0)-1.0

    vecx =

    -1 5 -4

    condition =

    6.0809

    和预期完全一致。

    2. 拉格朗日(Lagrange)插值

    1)插值函数基

    拉格朗日插值采用的是一种设计巧妙的多项式基,每个基底都是n-1次多项式,而每个基底函数当且仅当在第i个数据点处取1,在其余数据点均为零。这个多项式基是这样设计的:

    $$l_j(t)=\frac{(t-t_1)(t-t_2)...(t-t_{j-1})(t-t_{j+1})...(t-t_n)}{(t_j-t_1)(t_j-t_2)...(t_j-t_{j-1})(t_j-t_{j+1})...(t_j-t_n)}=\frac{\prod\limits_{k=1,k\neq j}^n(t-t_k)}{\prod\limits_{k=1, k\neq j}^n(t_j-t_k)}$$  因此就有:

    $$l_j(t_i)=\delta_{ij}, i,j=1,2,...n $$  其中,$\delta$ 为克罗内克(Kronecker)记号,当两个下标相等时为1,否则为零;也可以将 $\delta_{ij}$ 理解为一个二阶张量,即单位矩阵。只要将各个$t_i$ 带入定义式,上式是很容易验证的。这意味着拉格朗日插值的叠加系数的求解将会产生很好的性质,即:

    2)叠加系数

    需要求解的插值函数即:$f(t)=\sum\limits_{k=1}^nx_kl_k(t)$ ,而又已知:

    $$l_1(t_1)x_1+l_2(t_1)x_2+...+l_n(t_1)x_n=y_1$$

    $$l_1(t_2)x_1+l_2(t_2)x_2+...+l_n(t_2)x_n=y_2$$

    $$... ... ... ... ...$$

    $$l_1(t_n)x_1+l_2(t_n)x_2+...+l_n(t_n)x_n=y_n$$  写成矩阵形式就是:

    $$\begin{bmatrix}l_1(t_1)&l_2(t_1)&...&l_n(t_1)\\l_1(t_2)&l_2(t_2)&...&l_n(t_2)\\...&...&...&...\\l_1(t_n)&l_2(t_n)&...&l_n(t_n)\end{bmatrix} \begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=\begin{bmatrix}1&0&..&0\\0&1&..&0\\..&..&..&..\\0&0&..&1\end{bmatrix} \begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=I\boldsymbol{x}=\begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=\begin{bmatrix}y_1\\y_2\\...\\y_n\end{bmatrix}$$

    其矩阵即单位矩阵,因此直接得出 $x_i=y_i$ ,$f(t)=p_{n-1}(t)=y_1l_1(t)+y_2l_2(t)+...+y_nl_n(t)=\sum\limits_{k=1}^ny_kl_k(t)$

    3)问题条件和算法复杂度

    拉格朗日插值生成的系数矩阵为单位矩阵,完全不存在条件病态的问题,只需要将各个数据点的取值作为系数即可。同样地,求解系数也将不存在任何复杂度。

    但是,作为代价的是,函数求值开销较大。Horner嵌套算法可以用于单项式和牛顿插值表达式的求值,将总运算量大致控制在n次浮点数加法和n次浮点数乘法,但该算法不适用于拉格朗日插值的表达式。拉格朗日插值的求值的复杂度至少也要3n次浮点乘(除)法和2n次浮点加法以上,这还是在所有的系数(将插值系数和基底的分母合并以后的系数)都已经处理完成之后,而处理系数本身可能就需要 $n^2$ 级别的复杂度。此外,拉格朗日插值表达式也不利于求微分和积分;和牛顿插值相比,当新增数据点时不得不将所有的基底都改写,很不方便。总而言之,拉格朗日插值属于非常容易构造的一种插值,很适用于在理论上讨论某些问题,但在数值计算上仍具有很多劣势。

    4)算法实现

    实现拉格朗日多项式插值一种途径的MATLAB代码如下。此处的输出为多项式函数句柄。这些函数(句柄)只需要在函数名后面加括号变量即可调用,即polyfun(3)这样的形式。

    function [ polyfun ] = LagrangePI( vect, vecy )

    % 生成Lagrange插值多项式

    % 输入两个参数:插值点行向量vect,函数行向量vecy;输出一个参数:插值多项式函数句柄polyfun

    vecsize = size(vect, 2);

    syms t f term;

    f = 0;

    for i = 1:vecsize

    term = vecy(i);

    for j = 1:vecsize

    if (j ~= i)

    term = term*(t - vect(j))/(vect(i) - vect(j));

    end

    end

    f = f + term;

    end

    polyfun = matlabFunction(f);

    end

    但是,由于多项式形式的函数表达式带入后为符号型变量,这意味着每一项的系数都经历了单独计算,每一项的分子也需要单独计算,这将使得拉格朗日插值表达式的函数求值(function evaluation)的复杂度达到 $O(n^2)$ 量级;如果想要使得每次求值能够控制在 $O(n)$ 量级,就必须实现计算出除了含有未知量的函数基分子以外的全部系数,同时在求值时也需要一些技巧。按照如下的书写方法可以实现这一目的:

    function [ coefficients ] = newLagrangePI( vect, vecy )

    % 生成Lagrange插值多项式的系数(计算分母)

    % 输入两个参数:插值点行向量vect,函数行向量vecy;

    % 输出一个参数:插值多项式的系数行向量coefficients;

    vecsize = size(vect, 2);

    coefficients = zeros(1, vecsize);

    for i = 1:vecsize

    tmp = vecy(i); % 取得基底函数对应的系数y_i

    for j = 1:vecsize % 将其除以函数基底的分母

    if (j~=i)

    tmp = tmp/(vect(i) - vect(j));

    end

    end

    coefficients(i) = tmp;

    end

    end

    除了求系数的函数还需要一个特别的求值函数:

    function [ funeval ] = evaLagrangePI( coefficients, vect, vecy, t )

    % Lagrange插值多项式估值

    % 输入四个参数:Lagrange插值的完整系数行向量coefficients,插值点行向量vect,函数行向量vecy,求值点t;

    % 输出一个参数:函数在t处取值funeval

    vecsize = size(vect, 2);

    [found, index] = ismember(t, vect);

    if found % 如果求值点是原数据点,则直接返回原始信息中数据点的函数值

    funeval = vecy(index);

    else % 否则,先计算全部(t-t_i)的乘积

    funeval = 0; product = 1;

    for i = 1:vecsize

    product = product*(t - vect(i));

    end

    for i = 1:vecsize % 然后,计算每一项的值,乘以该项的系数并且除以该项分子不存在的那项(t-t_i)

    funeval = funeval + coefficients(i)*product/(t - vect(i));

    end

    end

    end

    同样是对于三点 $(-2,-27),(0,-1),(1,0)$ ,调用Lagrange插值方法:

    vect = [-2, 0, 1]; vecy = [-27, -1, 0];

    % 命令行输入

    coefficients = newLagrangePI(vect, vecy)

    % 命令行输出

    coefficients =

    -4.5000 0.5000 0

    % 命令行输入

    val = evaLagrangePI(coefficients, vect, vecy, -2)

    % 命令行输出

    val =

    -27

    % 命令行输入

    val = evaLagrangePI(coefficients, vect, vecy, 0.5)

    % 命令行输出

    val =

    0.5000

    所有的输出均和实际的多项式插值 $f(t)=p_2(t)=-1+5t-4t^2$ 吻合。

    3. 牛顿(Newton)插值

    1)插值函数基底

    单项式基底非常简洁,缺点是求解方程组所用的是稠密的范德蒙矩阵,可能非常病态,复杂度也很高;拉格朗日基底比较精巧复杂,因为求解的系数矩阵是单位矩阵,求解很简单很准确,缺点是生成表达式和函数求值复杂度很高。牛顿插值方法在二者之间提供了一个折衷选项:基底不如拉格朗日的函数基那么复杂,而求解又比单项式基底大大简化,这来源于牛顿插值选取的基底:$$\pi_j(t)=\prod\limits_{k=1}^{j-1}(t-t_k)=(t-t_1)(t-t_2)...(t-t_{j-1}), j=1,...,n$$  相对于拉格朗日基底的特殊性($l_j(t_i)=\delta_{ij}$),牛顿插值基底具有一个弱一点的性质:$$\pi_j(t_i)=0,\forall i

    2)叠加系数

    $$\pi_1(t_1)x_1+\pi_2(t_1)x_2+...+\pi_n(t_1)x_n=y_1$$

    $$\pi_1(t_2)x_1+\pi_2(t_2)x_2+...+\pi_n(t_2)x_n=y_2$$

    $$............$$

    $$\pi_1(t_n)x_1+\pi_2(t_n)x_2+...+\pi_n(t_n)x_n=y_n$$  写成矩阵形式:

    $$\begin{bmatrix}\pi_1(t_1)&\pi_2(t_1)&...&\pi_n(t_1)\\ \pi_1(t_2)&\pi_2(t_2)&...&\pi_n(t_2)\\...&...&...&...\\ \pi_1(t_n)&\pi_2(t_n)&...&\pi_n(t_n)\end{bmatrix} \begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=\begin{bmatrix}1&0&...&0\\1&t_2-t_1&...&0\\...&...&...&...\\1&t_n-t_1&...&(t_n-t_1)..(t_n-t_{n-1})\end{bmatrix}=\begin{bmatrix}y_1\\y_2\\...\\y_n\end{bmatrix}$$  也就是说,牛顿插值的系数求解矩阵为一个下三角矩阵。

    3)算法性质和算法复杂度

    我们知道对于下三角矩阵,利用向前代入法可以比较便利地解出,其时间复杂度为 $O(n^2)$ 。再来看生成这个下三角矩阵,复杂度也是 $O(n^2)$ 的运算量。因此求解插值系数的总复杂度即 $O(n^2)$ 量级,比稠密矩阵的求解少一个量级。当然,求解牛顿插值系数不一定需要显示地生成矩阵,然后采用矩阵分解的标准套路;牛顿插值有好几种生成系数的方法可供选择,包括差商方法等,采用递归或者迭代都可以获得良好的效果,还能避免上溢出。

    此外,牛顿插值的表达式在求值时适用Horner嵌套算法(太棒了!),这将把求值的复杂度控制在 $O(n)$ 的量级内,如果带上系数比拉格朗日插值表达式的求值要更高效。

    牛顿插值方法有如下优越的性质:

    3.1 当增加数据点时,可以仅仅通过添加一项函数基和增加一个系数,生成新的牛顿插值多项式。这其实是可以理解的,因为当新增点 $(t_{n+1},y_{n+1})$ 时,下三角系数矩阵所有的元素都没有发生任何变化,仅仅需要新增一列和一行即可,而在该矩阵右侧新增的一列全为零。这意味着所有的系数 $x_1,x_2,...x_n$ 不仅满足原线性方程组,也因此必定是新线性方程组解的部分。而基底部分也只是新增了一个基,所以新的插值多项式仅仅是老的插值多项式加一项而已,即 $f(t)^*=p_n(t)=p_{n-1}(t)+x_{n+1}\pi_{n+1}(t)$ 。对于新的这一项 $x_{n+1}\pi_{n+1}(t)$ 它的系数究竟如何取,只需要将新增的数据点带入即可求得:$$f(t_{n+1})^*=p_{n-1}(t_{n+1})+x_{n+1}\pi_{n+1}(t_{n+1})=y_{n+1}\quad \Rightarrow \quad x_{n+1}=\frac{y_{n+1}-p_{n-1}(t_{n+1})}{\pi_{n+1}(t_{n+1})}$$  生成新系数的复杂度大致需要一次函数求值和一次基底求值,大致为 $O(n)$ 复杂度。如果迭代地使用这一公式,就可以生成全部牛顿插值多项式系数,复杂度 $O(n^2)$ ,和矩阵解法也大致是持平的。

    3.2 差商法也可以实现生成牛顿插值多项式的系数。其中,差商 $f[]$ 的定义为:

    $$f[t_1, t_2,...t_k]=\frac{f[t_2, t_3, ... t_{k}-f[t_1, t_2,...t_{k-1}]}{t_k-t_1}$$  而牛顿多项式的系数则取自:$$x_j=f[t_1, t_2... t_j]$$  对于这个可以有证明:

    $$f[t_1]=y_1, x_1=y_1=f[t_1];\quad f[t_1, t_2]=\frac{f[t_2]-f[t_1]}{t_2-t_1}=\frac{y_2-y_1}{t_2-t_1},x_2=\frac{y_2-y_1}{t_2-t_1}=f[t_1, t_2]

    $$

    若$x_j=f[t_1, t_2, ...t_j]=\frac{f[t_2, t_3,...t_j]-f[t_1, t_2,...t_{j-1}]}{t_j-t_1}$ 对于任意 $j\leq k-1$ 成立,当 $j=k$ 时:

    ?考虑对于点 $(t_1, y_1), (t_2,y_2),...(t_{k-1},y_{k-1})$ 的 Newton 插值多项式 $p_1(t)$ ;对于点 $(t_2, y_2),(t_3, y_3),...$$(t_k, y_k)$ 的 Newton 插值多项式 $p_2(t)$ ,并且已知分差插值系数对任意 $j\leq k-1$ 均成立,因而有:

    $$

    p_1(t)=\sum\limits_{j=1}^{k-1}a_j\pi_j(t), \quad p_2(t)=\sum\limits_{j=2}^{k}b_j\pi_j(t),\qquad a_j=f[t_1,...t_{j}],b_j=f[t_2,...t_j]

    $$

    由 $p_1(t)$ 过点 $(t_1, y_1)$ 到 $(t_{k-1},y_{k-1})$ ,$p_2(t)$ 过点 $(t_2,y_2)$ 到 $(t_k,y_k)$ ,构造插值多项式:

    $$

    p(t)=\frac{t_k-t}{t_k-t_1}p_1(t)+\frac{t-t_1}{t_k-t_1}p_2(t)

    $$

    就有该多项式通过点 $(t_1, y_1)$ 到 $(t_k,y_k)$ ,因此即为所求的 Newton 插值多项式。带入 $p_1(t),p_2(t)$ 表达式,并比较等式两端最高次项系数即得:

    $$

    p(t)=\sum\limits_{j=1}^kx_j\pi_j(t)=\frac{t_k-t}{t_k-t_1}\sum\limits_{j=1}^{k-1}a_j\pi_j(t)+\frac{t-t_1}{t_k-t_1}\sum\limits_{j=2}^{k}b_j\pi_j‘(t)\\

    x_k=\frac{-1}{t_k-t_1}a_{k-1}+\frac{1}{t_k-t_1}b_k=\frac{f[t_2,...t_k]-f[t_1,...t_{k-1}]}{t_k-t_1}=f[t_1, ...t_k]\qquad \square

    $$

    这个证明我摘录自奥斯陆大学数学系的 Michael S. Floater 在 Newton Interpolation 讲义里面写的证明。

    4)算法实现

    根据3.1,可以通过新增节点的方法迭代地生成插值系数。利用这种思路的实现代码如下:

    function [ vecx_new, vect_new ] = newNPI( vect, vecx, newPoint )

    %Newton插值算法新增节点函数;

    % 输入三个参数:原插值点行向量vect,原插值系数行向量vecx,新增节点newPoint;

    % 输入两个参数:新系数行向量vecx_new,新插值点行向量vect_new;

    vecsize = size(vecx, 2);

    vecx_new = zeros(1, vecsize + 1); vecx_new(1:vecsize) = vecx;

    vect_new = zeros(1, vecsize + 1); vect_new(1:vecsize) = vect; vect_new(vecsize + 1) = newPoint(1);

    p_new = HornerNPI(vect, vecx, newPoint(1)); w_new = 1;

    for i = 1:vecsize

    w_new = w_new * (newPoint(1) - vect(i));

    end

    vecx_new(vecsize + 1) = (newPoint(2) - p_new) / w_new;

    end

    新增节点函数newNPI可以单独使用;同时也可以反复调用生成牛顿插值系数,如下:

    function [ polyfun, vecx ] = newNewtonPI( cvect, cvecy )

    % 使用新增节点函数逐渐更新产生Newton插值多项式系数;

    % 输入两个参数:插值点行向量cvect,插值系数行向量cvecx;

    % 输出两个参数:多项式函数句柄polyfun,系数行向量vecx;

    % 迭代生成系数行向量

    vect = cvect(1); vecx = cvecy(1);

    vecsize = size(cvect, 2);

    for i=2:vecsize

    [vecx, vect] = newNPI(vect, vecx, [cvect(i), cvecy(i)]);

    end

    % 采用Horner嵌套算法生成多项式函数句柄

    syms f t; f = vecx(vecsize);

    for i = vecsize-1:-1:1

    f = vecx(i) + (t - cvect(i)) * f;

    end

    polyfun = matlabFunction(f);

    end

    另一种方法是采用差商。以下是实现的代码。和之前的说法不同的是,本代码使用的并非递归,而是正向的类似函数值缓存的算法。

    function [ polyfun, vecx ] = recNewtonPI( vect, vecy )

    % 使用差商产生Newton插值多项式系数;

    % 输入两个参数:插值点行向量vect,函数取值cvecy;

    % 输出两个参数:多项式函数polyfun,系数行向量vecx;

    vecsize = size(vect, 2);

    Div = diag(vecy);

    % 差商生成系数行向量vecx

    for k = 1:vecsize-1

    for i = 1:vecsize-k

    Div(i, i+k) = (Div(i+1, i+k) - Div(i, i+k-1))/(vect(i+k) - vect(i));

    end

    end

    vecx = Div(1, :);

    % 生成多项式函数polyfun

    syms f t; f = vecx(vecsize);

    for i = vecsize-1:-1:1

    f = vecx(i) + (t - vect(i)) * f;

    end

    polyfun = matlabFunction(f);

    end

    但不论如何,产生的结果完全一致。用同样的例子:

    vect=[-2, 0, 1]; vecy=[-27, -1, 0];

    % 命令行输入1,调用新增节点方法

    [polyfun, vecx] = newNewtonPI(vect, vecy)

    % 命令行输入2,调用差商方法

    [polyfun, vecx] = recNewtonPI(vect, vecy)

    % 命令行输出1/2,完全相同

    polyfun =

    包含以下值的 function_handle:

    @(t)-(t.*4.0-1.3e1).*(t+2.0)-2.7e1

    vecx =

    -27 13 -4

    容易检验,该多项式函数正是原数据点的多项式插值函数。

    展开全文
  • 全域多项式插值的是在整个插值区域内形成一个多项式函数作为插值函数。关于多项式插值的基本知识,见“计算基本理论”。  在单项式基插值和牛顿插值形成的表达式中,求该表达式在某一点处的值使用的Horner嵌套...

      全域多项式插值指的是在整个插值区域内形成一个多项式函数作为插值函数。关于多项式插值的基本知识,见“计算基本理论”

      在单项式基插值和牛顿插值形成的表达式中,求该表达式在某一点处的值使用的Horner嵌套算法啊,见"Horner嵌套算法"。

    1. 单项式(Monomial)基插值

    1)插值函数基  单项式基插值采用的函数基是最简单的单项式:$$\phi_j(t)=t^{j-1}, j=1,2,...n;\quad f(t)=p_{n-1}(t)=x_1+x_2t+x_3t^2+...x_nt^{n-1}=\sum\limits_{j=1}^nx_jt^{j-1}$$  所要求解的系数即为单项式系数 $x_1,x_2,...x_n$ ,在这里仍然采用1,2,...n的下标记号而不采用和单项式指数对应的0,1,2,...,n-1的下标仅仅是出于和前后讨论一致的需要。

    2)叠加系数

      单项式基插值采用单项式函数基,若有m个离散数据点需要插值,设使用n项单项式基底:

    $$x_1+t_1x_2+t_1^2x_3+...+t_1^{n-1}x_n=y_1\\ x_1+t_2x_2+t_2^2x_3+...+t_2^{n-1}x_n=y_2\\ ......   ......   ......   ......   ......   ......\\ x_1+t_mx_2+t_m^2x_3+...+t_m^{n-1}x_n=y_m$$  系数矩阵为一 $m\times n$ 的矩阵($m\leq n$),范德蒙(Vandermonde)矩阵

    $$\begin{bmatrix}1&t_1&t_1^2&...&t_1^{n-1}\\1&t_2&t_2^2&...&t_2^{n-1}\\...&...&...&...&...\\1&t_n&t_n^2&...&t_n^{n-1}\end{bmatrix} \begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=\begin{bmatrix}y_1\\y_2\\...\\y_n\end{bmatrix}$$  根据计算基本理论中的讨论,多项式插值的函数基一定线性无关,且只要离散数据点两两不同,所构成的矩阵行也一定线性无关,这保证了矩阵一定行满秩。此时当且仅当m=n时,叠加系数有且仅有一组解。因此,n=插值基底的个数=离散数据点的个数=多项式次数+1。

    3)问题条件和算法复杂度

      生成范德蒙矩阵的复杂度大致在 $O(n^2)$ 量级;由于范德蒙矩阵并没有什么好的性质,既没有稀疏性,也没有对称性,因此只能使用标准的稠密矩阵分解(如LU)来解决,复杂度在 $O(n^3)$ 量级。因此,问题的复杂度在 $O(n^3)$ 量级。 

      范德蒙矩阵存在的问题是,当矩阵的维数越来越高的时候,解线性方程组时问题将越来越病态,条件数越来越大;从另一个角度来说,单项式基底本身趋势相近,次数增大时将越来越趋于平行(见下图)。这将造成随着数据点的增加,确定的叠加系数的不确定度越来越大,因此虽然单项式基很简单,进行插值时却往往不用这一方法。如果仍然采用单项式基底,有时也会进行两种可以改善以上问题的操作:平移(shifting)和缩放(scaling),即将 $((t-c)/d)^{j-1}$ 作为基底。常见的平移和缩放将所有数据点通过线性变换转移到区间[-1,1]中,即:$c=(t_1+t_n)/2,d=(t_n-t_1)/2$ 。

    4)算法实现 

      使用MATLAB实现单项式插值代码如下:

    function [ polyfunc, vecx, condition ] = MonoPI( vect, vecy, shift, scale )
    %    计算单项式型插值多项式系数
    %    输入四个参数:插值点行向量vect,插值点函数值行向量vecy,平移shift,压限scale;
    %    输出两个参数:插值多项式各项系数行向量vecx,矩阵条件数condition;
    
    % 设置缺省值:若只输入两个参数,则不平移不缩放
    if nargin==2
        shift = 0; scale = 1;
    end
    
    % 求解系数
    vecsize = size(vect, 2);
    basis = (vect - shift * ones(1, vecsize))/scale;    % 确定基底在各个数据点的取值向量basis
    Mat = vander(basis); condition = cond(Mat);    % 用vander命令生成basis的范德蒙矩阵并求条件数
    [L, U] = lu(Mat); vecx = (U\(L\vecy.')).'; vecx = fliplr(vecx);    % 标准lu分解解矩阵方程
    
    % 生成句柄函数polyfunc
    syms t;
    monomial = (t - shift)/scale; vecsize = size(vecx, 2); funeval = vecx(vecsize);
    for i = vecsize:-1:2    % 生成函数的算法采用Horner算法提高效率
        funeval = vecx(i - 1) + monomial*funeval;
    end
    polyfunc = matlabFunction(funeval, 'Vars', t);
    
    end
    

      比如对于点:$(-2,-27),(0,-1),(1,0)$ 它具有唯一的二次插值多项式:$p_2(t)=-1+5t-4t^2$ 。调用以上代码:

    % 命令行输入
    [polyfunc, vecx, condition] = MonoPI(vect, vecy)
    % 命令行输出
    polyfunc =
      包含以下值的 function_handle:
        @(t)-t.*(t.*4.0-5.0)-1.0
    vecx =
        -1     5    -4
    condition =
        6.0809
    

      和预期完全一致。

     

    2. 拉格朗日(Lagrange)插值

    1)插值函数基

      拉格朗日插值采用的是一种设计巧妙的多项式基,每个基底都是n-1次多项式,而每个基底函数当且仅当在第i个数据点处取1,在其余数据点均为零。这个多项式基是这样设计的:

    $$l_j(t)=\frac{(t-t_1)(t-t_2)...(t-t_{j-1})(t-t_{j+1})...(t-t_n)}{(t_j-t_1)(t_j-t_2)...(t_j-t_{j-1})(t_j-t_{j+1})...(t_j-t_n)}=\frac{\prod\limits_{k=1,k\neq j}^n(t-t_k)}{\prod\limits_{k=1, k\neq j}^n(t_j-t_k)}$$  因此就有:

    $$l_j(t_i)=\delta_{ij}, i,j=1,2,...n $$  其中,$\delta$ 为克罗内克(Kronecker)记号,当两个下标相等时为1,否则为零;也可以将 $\delta_{ij}$ 理解为一个二阶张量,即单位矩阵。只要将各个$t_i$ 带入定义式,上式是很容易验证的。这意味着拉格朗日插值的叠加系数的求解将会产生很好的性质,即:

    2)叠加系数

      需要求解的插值函数即:$f(t)=\sum\limits_{k=1}^nx_kl_k(t)$ ,而又已知:

    $$l_1(t_1)x_1+l_2(t_1)x_2+...+l_n(t_1)x_n=y_1$$

    $$l_1(t_2)x_1+l_2(t_2)x_2+...+l_n(t_2)x_n=y_2$$

    $$... ... ... ... ...$$

    $$l_1(t_n)x_1+l_2(t_n)x_2+...+l_n(t_n)x_n=y_n$$  写成矩阵形式就是:

    $$\begin{bmatrix}l_1(t_1)&l_2(t_1)&...&l_n(t_1)\\l_1(t_2)&l_2(t_2)&...&l_n(t_2)\\...&...&...&...\\l_1(t_n)&l_2(t_n)&...&l_n(t_n)\end{bmatrix} \begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=\begin{bmatrix}1&0&..&0\\0&1&..&0\\..&..&..&..\\0&0&..&1\end{bmatrix} \begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=I\boldsymbol{x}=\begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=\begin{bmatrix}y_1\\y_2\\...\\y_n\end{bmatrix}$$

      其矩阵即单位矩阵,因此直接得出 $x_i=y_i$ ,$f(t)=p_{n-1}(t)=y_1l_1(t)+y_2l_2(t)+...+y_nl_n(t)=\sum\limits_{k=1}^ny_kl_k(t)$

    3)问题条件和算法复杂度

      拉格朗日插值生成的系数矩阵为单位矩阵,完全不存在条件病态的问题,只需要将各个数据点的取值作为系数即可。同样地,求解系数也将不存在任何复杂度

      但是,作为代价的是,函数求值开销较大。Horner嵌套算法可以用于单项式和牛顿插值表达式的求值,将总运算量大致控制在n次浮点数加法和n次浮点数乘法,但该算法不适用于拉格朗日插值的表达式。拉格朗日插值的求值的复杂度至少也要3n次浮点乘(除)法和2n次浮点加法以上,这还是在所有的系数(将插值系数和基底的分母合并以后的系数)都已经处理完成之后,而处理系数本身可能就需要 $n^2$ 级别的复杂度。此外,拉格朗日插值表达式也不利于求微分和积分;和牛顿插值相比,当新增数据点时不得不将所有的基底都改写,很不方便。总而言之,拉格朗日插值属于非常容易构造的一种插值,很适用于在理论上讨论某些问题,但在数值计算上仍具有很多劣势。

    4)算法实现

       实现拉格朗日多项式插值一种途径的MATLAB代码如下。此处的输出为多项式函数句柄。这些函数(句柄)只需要在函数名后面加括号变量即可调用,即polyfun(3)这样的形式。

    function [ polyfun ] = LagrangePI( vect, vecy )
    %   生成Lagrange插值多项式
    %   输入两个参数:插值点行向量vect,函数行向量vecy;输出一个参数:插值多项式函数句柄polyfun
    vecsize = size(vect, 2);
    syms t f term;
    f = 0;
    for i = 1:vecsize
        term = vecy(i);
        for j = 1:vecsize
            if (j ~= i)
                term = term*(t - vect(j))/(vect(i) - vect(j));
            end
        end
        f = f + term;
    end
    polyfun = matlabFunction(f);
    end
    

      但是,由于多项式形式的函数表达式带入后为符号型变量,这意味着每一项的系数都经历了单独计算,每一项的分子也需要单独计算,这将使得拉格朗日插值表达式的函数求值(function evaluation)的复杂度达到 $O(n^2)$ 量级;如果想要使得每次求值能够控制在 $O(n)$ 量级,就必须实现计算出除了含有未知量的函数基分子以外的全部系数,同时在求值时也需要一些技巧。按照如下的书写方法可以实现这一目的:

    function [ coefficients ] = newLagrangePI( vect, vecy )
    %   生成Lagrange插值多项式的系数(计算分母)
    %   输入两个参数:插值点行向量vect,函数行向量vecy;
    %   输出一个参数:插值多项式的系数行向量coefficients;
    vecsize = size(vect, 2);
    coefficients = zeros(1, vecsize);
    for i = 1:vecsize
        tmp = vecy(i);    % 取得基底函数对应的系数y_i
        for j = 1:vecsize    % 将其除以函数基底的分母
            if (j~=i)
                tmp = tmp/(vect(i) - vect(j));
            end
        end
        coefficients(i) = tmp;
    end
    end
    

      除了求系数的函数还需要一个特别的求值函数:

    function [ funeval ] = evaLagrangePI( coefficients, vect, vecy, t )
    %   Lagrange插值多项式估值
    %   输入四个参数:Lagrange插值的完整系数行向量coefficients,插值点行向量vect,函数行向量vecy,求值点t;
    %   输出一个参数:函数在t处取值funeval
    vecsize = size(vect, 2);
    [found, index] = ismember(t, vect);
    if found    % 如果求值点是原数据点,则直接返回原始信息中数据点的函数值
        funeval = vecy(index);
    else    % 否则,先计算全部(t-t_i)的乘积
        funeval = 0; product = 1;
        for i = 1:vecsize
            product = product*(t - vect(i));
        end
        for i = 1:vecsize    % 然后,计算每一项的值,乘以该项的系数并且除以该项分子不存在的那项(t-t_i)
            funeval = funeval + coefficients(i)*product/(t - vect(i));
        end
    end
    end
    

      同样是对于三点 $(-2,-27),(0,-1),(1,0)$ ,调用Lagrange插值方法:

    vect = [-2, 0, 1]; vecy = [-27, -1, 0];
    % 命令行输入
    coefficients = newLagrangePI(vect, vecy)
    % 命令行输出
    coefficients =
       -4.5000    0.5000         0
    
    % 命令行输入
    val = evaLagrangePI(coefficients, vect, vecy, -2)
    % 命令行输出
    val =
       -27
    
    % 命令行输入
    val = evaLagrangePI(coefficients, vect, vecy, 0.5)
    % 命令行输出
    val =
        0.5000
    

      所有的输出均和实际的多项式插值 $f(t)=p_2(t)=-1+5t-4t^2$ 吻合。

     

    3. 牛顿(Newton)插值

    1)插值函数基底

      单项式基底非常简洁,缺点是求解方程组所用的是稠密的范德蒙矩阵,可能非常病态,复杂度也很高;拉格朗日基底比较精巧复杂,因为求解的系数矩阵是单位矩阵,求解很简单很准确,缺点是生成表达式和函数求值复杂度很高。牛顿插值方法在二者之间提供了一个折衷选项:基底不如拉格朗日的函数基那么复杂,而求解又比单项式基底大大简化,这来源于牛顿插值选取的基底:$$\pi_j(t)=\prod\limits_{k=1}^{j-1}(t-t_k)=(t-t_1)(t-t_2)...(t-t_{j-1}), j=1,...,n$$  相对于拉格朗日基底的特殊性($l_j(t_i)=\delta_{ij}$),牛顿插值基底具有一个弱一点的性质:$$\pi_j(t_i)=0,\forall i<j$$  求出的多项式形如:$f(t)=p_{n-1}(t)=\sum\limits_{j=1}^nx_j\pi_j(t)=x_1+x_2(t-t_1)+...+x_n(t-t_1)(t-t_2)...(t-t_{n-1})$

    2)叠加系数

    $$\pi_1(t_1)x_1+\pi_2(t_1)x_2+...+\pi_n(t_1)x_n=y_1$$

    $$\pi_1(t_2)x_1+\pi_2(t_2)x_2+...+\pi_n(t_2)x_n=y_2$$

    $$............$$

    $$\pi_1(t_n)x_1+\pi_2(t_n)x_2+...+\pi_n(t_n)x_n=y_n$$  写成矩阵形式:

    $$\begin{bmatrix}\pi_1(t_1)&\pi_2(t_1)&...&\pi_n(t_1)\\ \pi_1(t_2)&\pi_2(t_2)&...&\pi_n(t_2)\\...&...&...&...\\ \pi_1(t_n)&\pi_2(t_n)&...&\pi_n(t_n)\end{bmatrix} \begin{bmatrix}x_1\\x_2\\...\\x_n\end{bmatrix}=\begin{bmatrix}1&0&...&0\\1&t_2-t_1&...&0\\...&...&...&...\\1&t_n-t_1&...&(t_n-t_1)..(t_n-t_{n-1})\end{bmatrix}=\begin{bmatrix}y_1\\y_2\\...\\y_n\end{bmatrix}$$  也就是说,牛顿插值的系数求解矩阵为一个下三角矩阵

    3)算法性质和算法复杂度

      我们知道对于下三角矩阵,利用向前代入法可以比较便利地解出,其时间复杂度为 $O(n^2)$ 。再来看生成这个下三角矩阵,复杂度也是 $O(n^2)$ 的运算量。因此求解插值系数的总复杂度即 $O(n^2)$ 量级,比稠密矩阵的求解少一个量级。当然,求解牛顿插值系数不一定需要显示地生成矩阵,然后采用矩阵分解的标准套路;牛顿插值有好几种生成系数的方法可供选择,包括差商方法等,采用递归或者迭代都可以获得良好的效果,还能避免上溢出。

      此外,牛顿插值的表达式在求值时适用Horner嵌套算法(太棒了!),这将把求值的复杂度控制在 $O(n)$ 的量级内,如果带上系数比拉格朗日插值表达式的求值要更高效。

    牛顿插值方法有如下优越的性质:

    3.1 当增加数据点时,可以仅仅通过添加一项函数基和增加一个系数,生成新的牛顿插值多项式。这其实是可以理解的,因为当新增点 $(t_{n+1},y_{n+1})$ 时,下三角系数矩阵所有的元素都没有发生任何变化,仅仅需要新增一列和一行即可,而在该矩阵右侧新增的一列全为零。这意味着所有的系数 $x_1,x_2,...x_n$ 不仅满足原线性方程组,也因此必定是新线性方程组解的部分。而基底部分也只是新增了一个基,所以新的插值多项式仅仅是老的插值多项式加一项而已,即 $f(t)^*=p_n(t)=p_{n-1}(t)+x_{n+1}\pi_{n+1}(t)$ 。对于新的这一项 $x_{n+1}\pi_{n+1}(t)$ 它的系数究竟如何取,只需要将新增的数据点带入即可求得:$$f(t_{n+1})^*=p_{n-1}(t_{n+1})+x_{n+1}\pi_{n+1}(t_{n+1})=y_{n+1}\quad \Rightarrow \quad x_{n+1}=\frac{y_{n+1}-p_{n-1}(t_{n+1})}{\pi_{n+1}(t_{n+1})}$$  生成新系数的复杂度大致需要一次函数求值和一次基底求值,大致为 $O(n)$ 复杂度。如果迭代地使用这一公式,就可以生成全部牛顿插值多项式系数,复杂度 $O(n^2)$ ,和矩阵解法也大致是持平的。

    3.2 差商法也可以实现生成牛顿插值多项式的系数。其中,差商 $f[]$ 的定义为:

    $$f[t_1, t_2,...t_k]=\frac{f[t_2, t_3, ... t_{k}-f[t_1, t_2,...t_{k-1}]}{t_k-t_1}$$  而牛顿多项式的系数则取自:$$x_j=f[t_1, t_2... t_j]$$  对于这个可以有证明:


     

    $$f[t_1]=y_1, x_1=y_1=f[t_1];\quad f[t_1, t_2]=\frac{f[t_2]-f[t_1]}{t_2-t_1}=\frac{y_2-y_1}{t_2-t_1},x_2=\frac{y_2-y_1}{t_2-t_1}=f[t_1, t_2]
    $$
    若$x_j=f[t_1, t_2, ...t_j]=\frac{f[t_2, t_3,...t_j]-f[t_1, t_2,...t_{j-1}]}{t_j-t_1}$ 对于任意 $j\leq k-1$ 成立,当 $j=k$ 时:

    ​ 考虑对于点 $(t_1, y_1), (t_2,y_2),...(t_{k-1},y_{k-1})$ 的 Newton 插值多项式 $p_1(t)$ ;对于点 $(t_2, y_2),(t_3, y_3),...$$(t_k, y_k)$ 的 Newton 插值多项式 $p_2(t)$ ,并且已知分差插值系数对任意 $j\leq k-1$ 均成立,因而有:
    $$
    p_1(t)=\sum\limits_{j=1}^{k-1}a_j\pi_j(t), \quad p_2(t)=\sum\limits_{j=2}^{k}b_j\pi_j(t),\qquad a_j=f[t_1,...t_{j}],b_j=f[t_2,...t_j]
    $$
    由 $p_1(t)$ 过点 $(t_1, y_1)$ 到 $(t_{k-1},y_{k-1})$ ,$p_2(t)$ 过点 $(t_2,y_2)$ 到 $(t_k,y_k)$ ,构造插值多项式:
    $$
    p(t)=\frac{t_k-t}{t_k-t_1}p_1(t)+\frac{t-t_1}{t_k-t_1}p_2(t)
    $$
    就有该多项式通过点 $(t_1, y_1)$ 到 $(t_k,y_k)$ ,因此即为所求的 Newton 插值多项式。带入 $p_1(t),p_2(t)$ 表达式,并比较等式两端最高次项系数即得:
    $$
    p(t)=\sum\limits_{j=1}^kx_j\pi_j(t)=\frac{t_k-t}{t_k-t_1}\sum\limits_{j=1}^{k-1}a_j\pi_j(t)+\frac{t-t_1}{t_k-t_1}\sum\limits_{j=2}^{k}b_j\pi_j'(t)\\
    x_k=\frac{-1}{t_k-t_1}a_{k-1}+\frac{1}{t_k-t_1}b_k=\frac{f[t_2,...t_k]-f[t_1,...t_{k-1}]}{t_k-t_1}=f[t_1, ...t_k]\qquad \square
    $$

     


     这个证明我摘录自奥斯陆大学数学系的 Michael S. Floater 在 Newton Interpolation 讲义里面写的证明。

    4)算法实现

       根据3.1,可以通过新增节点的方法迭代地生成插值系数。利用这种思路的实现代码如下:

    function [ vecx_new, vect_new ] = newNPI( vect, vecx, newPoint )
    %	Newton插值算法新增节点函数;
    %   输入三个参数:原插值点行向量vect,原插值系数行向量vecx,新增节点newPoint;
    %   输入两个参数:新系数行向量vecx_new,新插值点行向量vect_new;
    vecsize = size(vecx, 2);
    vecx_new = zeros(1, vecsize + 1); vecx_new(1:vecsize) = vecx;
    vect_new = zeros(1, vecsize + 1); vect_new(1:vecsize) = vect; vect_new(vecsize + 1) = newPoint(1);
    p_new = HornerNPI(vect, vecx, newPoint(1)); w_new = 1;
    for i = 1:vecsize
        w_new = w_new * (newPoint(1) - vect(i));
    end
    vecx_new(vecsize + 1) = (newPoint(2) - p_new) / w_new;
    end
    

      新增节点函数newNPI可以单独使用;同时也可以反复调用生成牛顿插值系数,如下:

    function [ polyfun, vecx ] = newNewtonPI( cvect, cvecy )
    %    使用新增节点函数逐渐更新产生Newton插值多项式系数;
    %    输入两个参数:插值点行向量cvect,插值系数行向量cvecx;
    %    输出两个参数:多项式函数句柄polyfun,系数行向量vecx;
    
    %    迭代生成系数行向量
    vect = cvect(1); vecx = cvecy(1);
    vecsize = size(cvect, 2);
    for i=2:vecsize
        [vecx, vect] = newNPI(vect, vecx, [cvect(i), cvecy(i)]);
    end
    
    %    采用Horner嵌套算法生成多项式函数句柄
    syms f t; f = vecx(vecsize);
    for i = vecsize-1:-1:1
        f = vecx(i) + (t - cvect(i)) * f;
    end
    polyfun = matlabFunction(f);
    end
    

      另一种方法是采用差商。以下是实现的代码。和之前的说法不同的是,本代码使用的并非递归,而是正向的类似函数值缓存的算法。

    function [ polyfun, vecx ] = recNewtonPI( vect, vecy )
    %    使用差商产生Newton插值多项式系数;
    %    输入两个参数:插值点行向量vect,函数取值cvecy;
    %    输出两个参数:多项式函数polyfun,系数行向量vecx;
    vecsize = size(vect, 2);
    Div = diag(vecy);
    
    % 差商生成系数行向量vecx
    for k = 1:vecsize-1
        for i = 1:vecsize-k
            Div(i, i+k) = (Div(i+1, i+k) - Div(i, i+k-1))/(vect(i+k) - vect(i));
        end
    end
    vecx = Div(1, :);
    
    % 生成多项式函数polyfun
    syms f t; f = vecx(vecsize);
    for i = vecsize-1:-1:1
        f = vecx(i) + (t - vect(i)) * f;
    end
    polyfun = matlabFunction(f);
    end
    

      但不论如何,产生的结果完全一致。用同样的例子:

    vect=[-2, 0, 1]; vecy=[-27, -1, 0];
    
    % 命令行输入1,调用新增节点方法
    [polyfun, vecx] = newNewtonPI(vect, vecy)
    
    % 命令行输入2,调用差商方法
    [polyfun, vecx] = recNewtonPI(vect, vecy)
    
    % 命令行输出1/2,完全相同
    polyfun =
      包含以下值的 function_handle:
        @(t)-(t.*4.0-1.3e1).*(t+2.0)-2.7e1
    vecx =
       -27    13    -4
    

      容易检验,该多项式函数正是原数据点的多项式插值函数。

      

     

    转载于:https://www.cnblogs.com/gentle-min-601/p/9744395.html

    展开全文
  • matlab的应用-多项式函数及多项式拟合 Matlab 的应用- 多项式函数及多项式拟合 本节将向大家简要介绍 matlab 在多项式处理方面的应用。 多项式函数主要有: roots 求多项式的根 poly 特征多项式 polyval 多 项式的...

    41528d3028836879cd698677c3999917.gifmatlab的应用-多项式函数及多项式拟合

    Matlab 的应用- 多项式函数及多项式拟合 本节将向大家简要介绍 matlab 在多项式处理方面的应用。 多项式函数主要有: roots 求多项式的根 poly 特征多项式 polyval 多 项式的计算 poly2str(p, x )多项式代换 polyfit 多项式曲线拟合 conv 多项式乘法 deconv 多项式除法 polyder 微分多项式 下面我们将介绍这些函数的用法: 1,roots---求多项式的根 格式:roots(c) 说明:它表示计算一个多项式的根,此多项式系数是向量 c 的元素.如果 c 有 n+1 个元素,那么此多项式为: c(1)*x^n+c(2)*x^(n-1)+c(3)*x^(n-2)+--+c(n)*x+c(n+1) 2,poly---特征多项式 格式:poly(a) 说明:(1)如果 a 是一个 n 阶矩阵,poly(a) 是一个有 n+1 个元素的行向量,这 n+1 个 元素是特征多项式的系数(降幂排列). (2)如果 a 是一个 n 维向量,则 poly(a)是多项式(x-a(1))*(x-a(2))*(x-a(n)),即该多 项式以向量 a 的元素为根。 3,polyval—多项式计算 格式:polyval(v,s) 说明: 如果 v 是一个向量,它的元素是一个多项式的系数,那麽 polyval(v,s)是多项式在 s 处的值.如果 s 是一个矩阵或是一个向量,则多项式在 s 中所有元素上求值 例如: v=[1 2 3 4];vv=poly2str(v,’s’) (即 v=s^3+2*s^2+3*s+4) s=2; x=polyval(v,s) x =26 例如: v=[1 2 3 4]; s=[2 4]; polyval(v,s) ans=26 112 4,conv-多项式乘法 例:as=[1 2 3] as =1 2 3 >> az=[2 4 2 1] az =2 4 2 1 >> conv(as,az) ans =2 8 16 17 8 3 conv(az,as) ans =2 8 16 17 8 3 5,deconv- 多项式除法 例:deconv(az,as)%返回结果是商式的系数 ans = 2 0 [awwq,qw]=deconv(az,as)%awwq 是商式的系数,qw 是余式的系数 awwq =2 0 qw =0 0 -4 1 6,polyder 微分多项式 polyder(as) ans =2 2 7,polyfit-- 多项式曲线拟合 格式::polyfit(x,y,n) 说明:polyfit(x,y,n)是找 n 次多项式 p(x) 的系数,这些系数 满足在最小二乘法意义 下 p(x(i)) ~= y(i). “人口问题”是我国最大社会 问题之一,估计人口数量和发展趋势是我们制定一系 列相关政策的基础。有人口统计年鉴,可 查到我国从 1949 年至 1994 年人口数据 资料如下: 年份 1949 1954 1959 1964 1969 1974 1979 1984 1989 1994 人口 数 (百万) 541. 67 602.6 6 672.0 9 704.9 9 806.7 1 908.5 9 975.4 2 1034. 75 1106. 76 1176. 74 如何确定我国人口的发展变化规律呢? 一般地,我们采用下面的分析处理方法: 首先,在直角坐标系上作出人口数与年份的散点图象。观察随着年份的增加人口 数与年份变化关系,初步估计出他们之间的关系可近似地可看做一条直线。那么 我们如何把这条直线方程确定出来呢?并用他来估计 1999 年我国的人口数。方法一:先选择能反映直线变化的两个点,如(1949,541.67), (1984,1034.75)二 点确定一条直线,方程为 N = 14.088 t – 26915.842 ,代入 t =1999,得 N 12.46 亿 方法二:可以多取几组点对,确定几条直线方程,将 t = 1999 代入,分 别求出人口 数,在取其算数平值。 方法三:可采用“ 最小二乘法” 求出直线方程。 这就是曲线拟合的问题。 方法一与方法二都具有一定的局限性,下面我们重点介绍数据的曲线拟合。所谓 曲线拟合是指给定平面上的 n 个点(x i ,y i ),i=1,2,….,n,找出一条曲线使之与这些点 相当吻合,这个过程称之为曲线拟合。最常 见的曲线拟合是使用多项式来作拟合 曲线。曲线拟合最常用的方法是最小二乘法。其原理是求 f(x),使 达到最小。matlab 提供了基本的多项式曲线拟合函数命令 2 1 ] ) ( [ i n i i y x f      polyfit 格式::polyfit(x,y,n) 说明:polyfit(x,y,n)是找 n 次多项式 p(x) 的系数,这些系数 满足在最小二乘法意义 下 p(x(i)) ~= y(i). 已知一组数据,用什么样的曲线拟合最好呢? 可以根据散点 图进行直观观察,在 此基础上,选择几种曲线分别拟合,然后比 较, 观察那条曲 线的最小二乘指标最 小。 下面我们给出常用的曲线(下面的 为变量, 等为参数) , x y , a b 直线:y ax b   多项式:(一般情况下,n 不宜过高,n=2,3) 1 2 1 2 3 1 n n n n n y a x a x a x a x a          双曲线:y= a y b x   指数曲线: bx y ae  幂函数: b y ax 有些曲线的拟合,为了利用数学软件,在 拟合前需作变量替换,化 为对未知数的 线性函数。 思考:如果根据经验,曲线是双曲线 或指数曲线 及幂函数 a y b x   bx y ae  等,如何利用 matlab 的多项式拟合函数来作曲线拟合? b y ax  例2:在化学反应中,为研究某化合物的浓度随时间的变化规律。测得一组数据如 下表所示: x(分) 1 2 3 4 5 6 7 8 浓度 y 4 6.4 8.0 8.4 9.28 9.5 9.7 9.86 x(分) 9 10 11 12 13 14 15 16 浓度 y 10 10.2 10.32 10.42 10.5 10.55 10.58 10.6 试求浓度 y 与时间 t 的经验函数关系。并推断第 20 、40 分钟时的浓度值。 本题是一个可以用数据的曲线拟合来解决的问题。下面是利用 matlab 编的一段 程序。 clear; %录入数据 xy=[1 4 2 6.4 3 8.0 4 8.45 9.286 9.57 9.7 8 9.86 9 1010 10.2 11 10.32 12 10.42 13 10.5 14 10.55 15 10.58 16 10.6]; x=xy(:,1); y=xy(:

    展开全文
  • 在本笔记中,我们将从简单易懂的多项式函数拟合实验出发,谈一谈如今做机器学习绕不开的三个重要概念:模型选择、欠拟合和过拟合,并且进一步挖掘如何选择模型、如何避免欠拟合和过拟合问题。本笔记主要从下面 ——...
  • 复现多项式函数拟合这个demo时遇见的问题。 先贴代码再详说: import numpy as np import torch import torch.nn as nn import torch.utils.data as Data # 1.生成特征 n_train,n_test=100,100 features=torch....
  • 目录多项式泰勒展开式牛顿迭代牛顿迭代应用P4726 【模板】多项式指数函数多项式 exp) 点我看多项式全家桶(●^◡_◡◡​^●) 多项式 泰勒展开式 牛顿迭代 牛顿迭代应用 牛顿迭代yyds,只用三行就完成了...
  • 训练误差(training error)模型在训练数据集上表现出的误差。 泛化误差(generalization error)模型在任意一个测试数据样本上表现出的误差的期望,并常常通过测试数据集上的误差来近似。 欠拟合(...
  • 众所周知,生成函数是OI中的计数利器,而很多生成函数的题目需要快速计算式子中的多项式运算,所以本篇主要是介绍多项式运算的. 值得注意的是,这里很多奇怪的多项式运算本来是不存在模xnx^nxn意义下的定义的,但是...
  • matlab----多项式函数

    千次阅读 2018-12-01 16:36:41
    多项式 多项式的表示 一个p阶的多项式可以用一个含有p+1个元素的向量表示,MATLAB表示多项式为包含由下降幂排列的系数的行向量,例如 p(x)=2*x^2+1 可以表示为 p = [2 0 1]; conv 多项式的乘法。 p1=[1 1];%它是x+1...
  • 多项式函数以其简单的结构和性质在数值逼近中起到重要的作用,多项式的定义是什么?以下是学习啦小编为大家整理的关于多项式的定义,欢迎大家前来阅读!多项式的定义多项式是代数学中的基础概念,是由称为不定元的变量...
  • 1010 一元多项式求导设计函数求一元多项式的导数。(注:x​n​​ (n为整数)的一阶导数为nx​n−1​​ 。) 输入格式: 以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过 1000 的整数)。数字间以空格...
  • 1)勒让德多项式(https://zh.wikipedia.org/wiki/%E5%8B%92%E8%AE%A9%E5%BE%B7%E5%A4%9A%E9%A1%B9%E5%BC%8F) 2)连带(缔合,伴随)勒让德多项式,Associated Legendre Polynomial:...
  • 勒让德函数(Legendre多项式)

    千次阅读 2019-07-20 12:30:17
    文章目录勒让德函数定义勒让德...勒让德函数指以下勒让德微分方程的解: (1−x2)d2P(x)dx2−2xdP(x)dx+n(n+1)P(x)=0(1-x^2)\frac{d^2P(x)}{dx^2} -2x\frac{dP(x)}{dx}+n(n+1)P(x)=0 (1−x2)dx2d2P(x)​−2xdxdP(x...
  • 多项式

    千次阅读 2013-09-17 14:18:32
    多项式中每一个 x n 皆称之为多项式的项 次数:多项式 x n 中每一项的n为此项的次数 同次项:若有多个多项式,其中每一项的 x k 项称之为同次项 首项:指多项式的项中次数最大者,若多项式首项为n,则称此多项式为n...
  • 生成函数+斯特林数+二项式反演+经典对反演+多项式求对求逆
  • 设计函数求一元多项式的导数。 题目在此 输入格式: 以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。 输出格式: 以与输入相同的格式输出导数多项式非零项的系数和指数...
  • 多项式函数是形式比较简单的函数: f(x)=a0+a1(x-x1)+a2(x-x2)^2+a3(x-x3)^3... 多项式拟合一般,用多项式函数逼近一个函数, 常用方法为利用泰勒公式,将函数展开为拉格朗日级数麦克劳林级数等等
  • 多项式计算机

    2019-05-21 20:54:59
    @## 标题[TOC]多项式计算机:实现两个多项式的相加、相减及相乘计算,并输出升幂和降幂两种结果形式。 声明: ​ 此博客所有内容均基于个人对数据结构的理解,仅供参考,若发现任何...链表的一个结点包括一个...
  • [duō xiàng shì]多项式语音编辑锁定讨论上传视频在数学中,由若干个单项式相加组成的代数式叫做...中文名多项式外文名polynomial适用领域应用学科数学定义连续函数多项式定义编辑语音在数学中,多项式(polynom...
  • 多项式回归

    2020-02-26 19:32:29
    多项式回归 什么是多项式回归? ​ 多项式回归是一种回归算法(多项式回归是基于线性回归的扩展,多项式回归是用于解决非线性的回归问题). 对于这样的数据,虽然我们可以使用线性回归来拟合这些数据,但是这些数据更...
  • MATLAB多项式 - Matlab教程MATLAB指多项式行向量系数降幂排序。例如,方程 P(x) = x4 + 7x3 - 5x + 9 可以表示为:p = [1 7 0 -5 9];计算多项式polyval 函数用于将指定的值 - 计算多项式。例如,要计算我们以前的...
  • 文章目录1.0多项式的定义:1.1问题等价:多项式拟合=关于多项式系数 W 的线性函数的求解1.2问题实质:通过误差函数来对拟合进行评估,并得出最优的多项式系数2.0误差函数的定义2.1误差函数也称为损失函数lost或者...
  • 多项式加法

    2019-08-06 19:31:06
    多项式加法 总时间限制: 1000ms 内存限制: 5000kB 描述 我们经常遇到两多项式相加的情况,在这里,我们就需要用程序来模拟实现把两个多项式相加到一起。首先,我们会有两个多项式,每个多项式是独立的一行,每...
  • 多项式 由若干个单项式相加组成的代数式叫做多项式 形如:f(x)=∑ni=0aixif(x)=∑i=0naixif(x)=\sum_{i=0}^{n}a_ix^i, deg&...生成函数 形如∑∞i=0aixi∑i=0∞aixi\sum_{i=0}^\infty a...
  • 多项式模型与多项式拟合

    千次阅读 2020-08-17 20:36:39
    3. 多项式模型 (一元多次方程) 3.1 多项式拟合 在有些数据分布中,使用一条曲线比直线能更好拟合数据,这就需要用到多项式拟合。如下图所示分布: 多项式的一般形式: y=p0xn+p1xn−1+p2xn−2+p3xn−3+...+pn y=p_{...
  • 多项式乘法 多项式求逆 多项式求导 多项式积分 多项式乘法 这个大家应该都会吧 还是简单推推式子吧。 已知的: A(x)=∑i=0naixiA(x)=\sum_{i=0}^na_ix^iA(x)=∑i=0n​ai​xi B(x)=∑i=0mbixiB(x)=\sum_{i=0}^mb_ix^...
  • 编写求其导函数的算法,要求利用原多项式中的结 点空间存放其导函数多项式),同时释放所有无 用(被删)结点。 实现下列函数: void Difference(LinkedPoly &pa); /* 稀疏多项式 pa 以循环链表作存储结构, ...
  • 非线性函数包括:指数函数、幂函数、对数函数、多项式函数等等基本初等函数 从数学的角度如何区别于什么是线性函数,什么是非线性函数呢? 对于一个函数y=f(x)来说,如果他是有线性的,则必须要满足两个法则: 比例...
  • Legendre多项式

    千次阅读 2016-06-25 11:38:44
    勒让德函数指以下勒让德微分方程的解:   为求解方便一般也写成如下施图姆-刘维尔形式   上述方程及其解函数因法国数学家阿德里安-马里·勒让德而得名。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,537
精华内容 7,814
关键字:

多项式函数指的是