lagrange approximation -c ++

时间:2011-07-09 12:39:05

标签: c++ numerical

我更新了代码。 我想要做的是在指针d中保存每个拉格朗日的系数值。(例如对于L1(x)d [0]将是“x-x2 / x1-x2”,d 1将是( x-x2 / x1-x2)*(x-x3 / x1-x3)等。

我的问题是

1)如何初始化d(我做了d [0] =(zx [i])/(x [k] -x [i])但我认为它不对“d [0]”

2)如何初始化L_coeff。 (我使用的是L_coeff = new double [0],但我不确定它是否正确。

练习是: 使用5个点找出y(x)= cos(πx),x∈-1,1的拉格朗日多项式逼近 (x = -1,-0.5,0,0.5和1)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>

using namespace std;

const double pi=3.14159265358979323846264338327950288;

// my function
double f(double x){

return (cos(pi*x));

}


//function to compute lagrange polynomial
double lagrange_polynomial(int N,double *x){
//N = degree of polynomial

double z,y;
double *L_coeff=new double [0];//L_coefficients of every Lagrange L_coefficient
double *d;//hold the polynomials values for every Lagrange coefficient
int k,i;
//computations for finding lagrange polynomial
//double sum=0;

for (k=0;k<N+1;k++){
        for ( i=0;i<N+1;i++){
            if (i==0) continue;
            d[0]=(z-x[i])/(x[k]-x[i]);//initialization
            if (i==k) L_coeff[k]=1.0;
            else if (i!=k){
            L_coeff[k]*=d[i];

                      }

           }

cout <<"\nL("<<k<<") = "<<d[i]<<"\t\t\tf(x)= "<<f(x[k])<<endl;
}

}

int main()
{

    double deg,result;
    double *x;


    cout <<"Give the degree of the polynomial :"<<endl;
    cin >>deg;

    for (int i=0;i<deg+1;i++){
    cout <<"\nGive the points of interpolation : "<<endl;
    cin >> x[i];
    }

    cout <<"\nThe Lagrange L_coefficients are: "<<endl;
    result=lagrange_polynomial(deg,x);



    return 0;
}

Here is an example of lagrange polynomial

This is the solution i have done

3 个答案:

答案 0 :(得分:6)

由于这似乎是家庭作业,我不打算给你一个详尽的答案,而是试着让你走上正确的轨道。

  • 您如何在计算机软件中表示多项式?您希望存档为<3> ^ 3 + 5x ^ 2-4等符号表达式的直观版本对于进一步计算非常不实用。
  • 通过保存(并输出)它的系数来完全定义多项式。

您正在做的是希望C ++为您做一些代数操作,并使用符号变量简化您的产品。如果没有很多努力,C ++就无法做到这一点。

您有两种选择:

  • 使用可以进行符号操作的合适的计算机代数系统(Maple或Mathematica就是一些例子)
  • 如果你受C ++约束,你必须多考虑如何计算多项式的单个系数。您的程序输出只能是一个数字列表(当然,根据符号表达式,您可以将其格式化为漂亮的字符串)。

希望这会给你一些如何开始的想法。

编辑1

您的代码中仍然有一个未定义的表达式,因为您从未将任何值设置为y。这会使prod*=(y-x[i])/(x[k]-x[i])作为不返回有意义数据的表达式。 C ++只能使用数字,y现在不是你的数字,但你认为它是符号。

如果要在代码中设置1,则可以评估 lagrange近似值,例如值y=1。这会给你(就我现在所见)正确的函数值,但没有函数本身的描述。

也许你应该先拿一支笔和一张纸,然后尝试将表达式写成精确的数学。尝试真正掌握您想要计算的内容。如果你那样做,也许你回到这里告诉我们你的想法。这应该可以帮助您了解那里发生了什么。

永远记住:C ++需要数字,而不是符号。每当你的纸上的表达式中有一个符号,你不知道你的价值时,你可以找到一种方法来计算已知值的值,或者你必须消除使用这个符号计算的需要。

P.S。:在multiple讨论区中同时发布相同问题并不是一种好的方式......

编辑2

现在您在y = 0.3处评估函数。如果要评估多项式,这是要采用的方法。但是,正如您所说,您需要多项式的所有系数。

同样,我仍然觉得你不理解问题背后的数学。也许我会给你一个小例子。我将使用维基百科文章中使用的符号。

假设我们有k = 2且x = -1,1。此外,为了简单起见,我只需命名你的cos函数f。 (没有乳胶,符号会变得相当难看......)然后拉格朗日多项式被定义为

f(x_0) * l_0(x) + f(x_1)*l_1(x)

其中(通过再次简化符号

l_0(x)= (x - x_1)/(x_0 - x_1) = -1/2 * (x-1) = -1/2 *x  + 1/2
l_1(x)= (x - x_0)/(x_1 - x_0) = 1/2 * (x+1)  = 1/2 * x  + 1/2

所以,你的拉格朗日多项式是

  f(x_0) * (-1/2 *x  + 1/2) + f(x_1) * 1/2 * x  + 1/2
= 1/2 * (f(x_1) - f(x_0)) * x     +     1/2 * (f(x_0) + f(x_1))

因此,您想要计算的系数为1/2 *(f(x_1) - f(x_0))和1/2 *(f(x_0)+ f(x_1))。

您现在的任务是找到一种算法来完成我所做的简化,但不使用符号。如果您知道如何计算l_j的系数,那么基本上就完成了,因为您可以将那些乘以相应的f值相加。

因此,即使进一步细分,您也必须找到一种方法,在逐个组件的基础上将l_j中的商相互相乘。弄清楚这是如何完成的,你几乎完成了。

编辑3

好的,让我们不那么模糊。

我们首先想要计算L_i(x)。这些只是线性函数的产物。如前所述,我们必须将每个多项式表示为系数数组。为了好的风格,我将使用std::vector而不是此数组。然后,我们可以定义包含L_1(x)系数的数据结构,如下所示:

std::vector L1 = std::vector(5); 
// Lets assume our polynomial would then have the form 
// L1[0] + L2[1]*x^1 + L2[2]*x^2 + L2[3]*x^3 + L2[4]*x^4

现在我们想用值填充这个多项式。

// First we have start with the polynomial 1 (which is of degree 0)
// Therefore set L1 accordingly:
L1[0] = 1;
L1[1] = 0; L1[2] = 0; L1[3] = 0; L1[4] = 0;
// Of course you could do this more elegant (using std::vectors constructor, for example)
for (int i = 0; i < N+1; ++i) {
    if (i==0) continue;  /// For i=0, there will be no polynomial multiplication
    // Otherwise, we have to multiply L1 with the polynomial
    // (x - x[i]) / (x[0] - x[i])
    // First, note that (x[0] - x[i]) ist just a scalar; we will save it:
    double c = (x[0] - x[i]);
    // Now we multiply L_1 first with (x-x[1]). How does this multiplication change our 
    // coefficients? Easy enough: The coefficient of x^1 for example is just
    // L1[0] - L1[1] * x[1]. Other coefficients are done similary. Futhermore, we have
    // to divide by c, which leaves our coefficient as
    // (L1[0] - L1[1] * x[1])/c. Let's apply this to the vector:
    L1[4] = (L1[3] - L1[4] * x[1])/c;
    L1[3] = (L1[2] - L1[3] * x[1])/c;
    L1[2] = (L1[1] - L1[2] * x[1])/c;
    L1[1] = (L1[0] - L1[1] * x[1])/c;
    L1[0] = (      - L1[0] * x[1])/c; 
    // There we are, polynomial updated.
}

当然,必须对所有L_i进行此操作。之后,必须添加L_i并与函数相乘。那是你要弄明白的。 (请注意,我在那里做了很多低效的工作,但我希望这有助于你更好地理解细节。)

希望这能让您了解如何继续。

答案 1 :(得分:1)

变量y实际上不是代码中的变量,而是代表拉格朗日逼近的变量P(y)

因此,您必须直接但象征性地理解计算prod*=(y-x[i])/(x[k]-x[i])sum+=prod*f

你可以通过一系列

来定义近似值来解决这个问题
c[0] * y^0 + c[1] * y^1 + ...

由代码中的数组c[]表示。然后你可以,例如实现乘法

d = c * (y-x[i])/(x[k]-x[i])

类似系数

d[i] = -c[i]*x[i]/(x[k]-x[i]) + c[i-1]/(x[k]-x[i])

您必须以组件为基础实施添加和分配。

结果将始终是变量y中系列表示的系数。

答案 2 :(得分:0)

除了现有的回复之外,还有一些评论。

  

练习是:使用5个点(x = -1,-0.5,0,0.5和1)找出y(x)= cos(πx),x∈[-1,1]的拉格朗日多项式近似

main()做的第一件事就是要求多项式的次数。你不应该这样做。多项式的次数由控制点的数量完全指定。在这种情况下,你应该构造 唯一的四阶拉格朗日多项式,它通过五个点(x i ,cos(πx i )),其中x i 值是那五个指定点。

  

const double pi=3.1415;

这个值对于浮点数不好,更不用说加倍了。您应该使用类似const double pi=3.14159265358979323846264338327950288;

的内容

或者更好的是,根本不要使用pi。您应该确切知道与给定x值对应的y值。什么是cos(-π),cos(-π/ 2),cos(0),cos(π/ 2)和cos(π)?