【问题标题】:How to calculate coefficients of polynomial using Lagrange interpolation如何使用拉格朗日插值计算多项式系数
【发布时间】:2012-03-25 14:27:53
【问题描述】:

我需要使用拉格朗日interpolation polynomial 计算多项式的系数,作为我的作业,我决定用Javascript 来完成。

这是拉格朗日多项式 (L(x)) 的定义

拉格朗日基多项式定义如下

计算特定 X 的 y 值(W(x) 函数)很简单,但我需要计算多项式的系数([a0, a1, ..., an] 的数组)我需要对 n

我有在第一个方程中计算分母的函数

function denominator(i, points) {
   var result = 1;
   var x_i = points[i].x;
   for (var j=points.length; j--;) {
      if (i != j) {
        result *= x_i - points[j].x;
      }
   }
   return result;
}

以及使用 horner 方法返回 y 的函数(我也有使用画布的绘图函数)

function horner(array, x_scale, y_scale) {
   function recur(x, i, array) {
      if (i == 0) {
         return x*array[0];
      } else {
         return array[i] + x*recur(x, --i, array);
      }
   }
   return function(x) {
      return recur(x*x_scale, array.length-1, array)*y_scale;
   };
}

任何人都知道执行此操作的算法,或者知道如何计算这些系数

【问题讨论】:

标签: javascript polynomial-math


【解决方案1】:

好吧,你可以用幼稚的方式来做。用它的系数数组表示一个多项式,数组

[a_0,a_1,...,a_n]

对应于a_0 + a_1*X + ... + a_n*X^n。我不擅长 JavaScript,所以必须使用伪代码:

interpolation_polynomial(i,points)
    coefficients = [1/denominator(i,points)]
    for k = 0 to points.length-1
        if k == i
            next k
        new_coefficients = [0,0,...,0] // length k+2 if k < i, k+1 if k > i
        if k < i
            m = k
        else
            m = k-1
        for j = m downto 0
            new_coefficients[j+1] += coefficients[j]
            new_coefficients[j] -= points[k]*coefficients[j]
        coefficients = new_coefficients
    return coefficients

从常数多项式1/((x_1-x_0)* ... *(x_i-x_{i-1})*(x_i-x_{i+1})*...*(x_i-x_n)) 开始,乘以X - x_k 得到所有k != i。这样就给出了 Li 的系数,然后你只需将它们与 yi 相乘(如果你传递 y,你可以通过将 coefficients 初始化为 y_i/denominator(i,points) 来做到这一点-values 作为参数),最后将所有系数相加。

polynomial = [0,0,...,0] // points.length entries
for i = 0 to points.length-1
    coefficients = interpolation_polynomial(i,points)
    for k = 0 to points.length-1
        polynomial[k] += y[i]*coefficients[k]

计算每个Li是O(n²),所以总计算量是O(n³)。

更新:在您的 jsFiddle 中,除了(现在已更正)我所做的起始索引错误之外,您在多项式乘法循环中还有一个错误,应该是

for (var j= (k < i) ? (k+1) : k; j--;) {
     new_coefficients[j+1] += coefficients[j];
     new_coefficients[j] -= points[k].x*coefficients[j];
}

由于您在测试时将j递减,因此需要从高一开始。

这还不能产生正确的插值,但至少比以前更明智。

另外,在您的 horner 函数中,

function horner(array, x_scale, y_scale) {
   function recur(x, i, array) {
      if (i == 0) {
         return x*array[0];
      } else {
         return array[i] + x*recur(x, --i, array);
      }
   }
   return function(x) {
      return recur(x*x_scale, array.length-1, array)*y_scale;
   };
}

你将最高系数乘以x,应该是

if (i == 0) {
    return array[0];
}

相反。不过还是没有好结果。

Update2:最终的错字修复,以下工作:

function horner(array, x_scale, y_scale) {
   function recur(x, i, array) {
      if (i == 0) {
         return array[0];
      } else {
         return array[i] + x*recur(x, --i, array);
      }
   }
   return function(x) {
      return recur(x*x_scale, array.length-1, array)*y_scale;
   };
}

// initialize array
function zeros(n) {
   var array = new Array(n);
   for (var i=n; i--;) {
     array[i] = 0;
   }
   return array;
}

function denominator(i, points) {
   var result = 1;
   var x_i = points[i].x;
   for (var j=points.length; j--;) {
      if (i != j) {
        result *= x_i - points[j].x;
      }
   }
    console.log(result);
   return result;
}

// calculate coefficients for Li polynomial
function interpolation_polynomial(i, points) {
   var coefficients = zeros(points.length);
    // alert("Denominator " + i + ": " + denominator(i,points));
   coefficients[0] = 1/denominator(i,points);
    console.log(coefficients[0]);
    //new Array(points.length);
   /*for (var s=points.length; s--;) {
      coefficients[s] = 1/denominator(i,points);
   }*/
   var new_coefficients;

   for (var k = 0; k<points.length; k++) {
      if (k == i) {
        continue;
      }
      new_coefficients = zeros(points.length);
       for (var j= (k < i) ? k+1 : k; j--;) {
         new_coefficients[j+1] += coefficients[j];
         new_coefficients[j] -= points[k].x*coefficients[j];
      }   
      coefficients = new_coefficients;
   }
   console.log(coefficients);
   return coefficients;
}

// calculate coefficients of polynomial
function Lagrange(points) {
   var polynomial = zeros(points.length);
   var coefficients;
   for (var i=0; i<points.length; ++i) {
     coefficients = interpolation_polynomial(i, points);
     //console.log(coefficients);
     for (var k=0; k<points.length; ++k) {
       // console.log(points[k].y*coefficients[k]);
        polynomial[k] += points[i].y*coefficients[k];
     }
   }
   return polynomial;
}

【讨论】:

  • 我不能让它在 JS 中工作,这行是什么意思 coefficients = [1/denominator(i,points)] 用一个元素创建数组或创建每个元素相同或每个元素不同?
  • 第一个,一个元素的数组。您还可以创建一个更长的数组并将所有其他条目设置为 0。查看您的 horner 函数,我只注意到您使用数组作为系数,a[0] 对应于最高功率的系数,而我将其设为常数学期。如果您没有注意到这一点,那将导致完全错误的结果。你必须反转一些数组。
  • 我创建了一个 jsfiddle jsfiddle.net/JdwNw 并且 interpolation_polynomial 函数中只有 1 和最后一个多项式返回一些值。我认为我会接受答案并为此创建另一个问题。
  • 摆弄一下小提琴,denominator(i,points) 往往会返回NaN。不过,我不知道为什么。
  • @daniel-fisher 我将console.log(result) 放在分母函数中,将console.log(coefficients[0]); 放在插值多项式函数中,它们都返回数字。
【解决方案2】:

如果您使用“Beginner's guide to mapping simplexes affinely ”,“拉格朗日插值”部分中介绍的拉格朗日插值矩阵形式,您可以相对容易地找到拉格朗日插值多项式的系数。恐怕,我不知道 JavaScript 可以为您提供合适的代码,但我使用了一点 Python,也许以下内容会有所帮助(抱歉代码风格不好——我是数学家,而不是程序员)

import numpy as np
# input
x = [0, 2, 4, 5]  # <- x's
y = [2, 5, 7, 7]  # <- y's
# calculating coefficients
M = [[_x**i*(-1)**(i*len(x)) for _x in x] for i in range(len(x))]
C = [np.linalg.det((M+[y]+M)[d:d+len(x)]) for d in range(len(x)+1)]
C = (C / C[0] * (-1)**(len(x)+1) )[1:]
# polynomial lambda-function
poly = lambda _x: sum([C[i] * _x**i for i in range(len(x))])
# output and tests
print("Coefficients:\n", C)
print("TESTING:")
for _x, _y in zip(x, y):
    result = "[OK]" if np.allclose(_y, poly(_x)) else "[ERROR]"
    print(_x, " mapped to: ", poly(_x), " ; expected: ", _y, result)

此代码计算拉格朗日插值多项式的系数,打印它们,并测试给定的 x 映射到预期的 y。您可以使用Google colab 测试此代码,因此您无需安装任何东西。大概,你可以把它翻译成JS。

【讨论】:

  • 我认为它没有任何用处,因为这需要使用 numpy 来隐藏 API 背后的所有算法。所以它没有告诉你这实际上是如何工作的。这是代码太多高级 numpy,无法在 Python 以外的其他语言中使用。
  • 我需要一些时间来思考......也许我可以找到一种方法来尽量减少 numpy 的使用。
  • 看来,唯一对系数计算至关重要的 numpy 函数是行列式(numpy.linalg.det)——我能够删除所有其他函数(用于测试的 numpy.allclose 除外仅)。
【解决方案3】:

此代码将确定从常数项开始的系数。

var xPoints=[2,4,3,6,7,10]; //example coordinates
var yPoints=[2,5,-2,0,2,8];
var coefficients=[];
for (var m=0; m<xPoints.length; m++) coefficients[m]=0;
    for (var m=0; m<xPoints.length; m++) {
        var newCoefficients=[];
        for (var nc=0; nc<xPoints.length; nc++) newCoefficients[nc]=0;
        if (m>0) {
            newCoefficients[0]=-xPoints[0]/(xPoints[m]-xPoints[0]);
            newCoefficients[1]=1/(xPoints[m]-xPoints[0]);
    } else {
        newCoefficients[0]=-xPoints[1]/(xPoints[m]-xPoints[1]);
        newCoefficients[1]=1/(xPoints[m]-xPoints[1]);
    }
    var startIndex=1; 
    if (m==0) startIndex=2; 
    for (var n=startIndex; n<xPoints.length; n++) {
        if (m==n) continue;
        for (var nc=xPoints.length-1; nc>=1; nc--) {
            newCoefficients[nc]=newCoefficients[nc]*(-xPoints[n]/(xPoints[m]-xPoints[n]))+newCoefficients[nc-1]/(xPoints[m]-xPoints[n]);
        }
        newCoefficients[0]=newCoefficients[0]*(-xPoints[n]/(xPoints[m]-xPoints[n]));
    }    
    for (var nc=0; nc<xPoints.length; nc++) coefficients[nc]+=yPoints[m]*newCoefficients[nc];
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    相关资源
    最近更新 更多