Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何求多项式方程的系数?_C++_C_Numerical Methods_Numerical_Numerical Computing - Fatal编程技术网

C++ 如何求多项式方程的系数?

C++ 如何求多项式方程的系数?,c++,c,numerical-methods,numerical,numerical-computing,C++,C,Numerical Methods,Numerical,Numerical Computing,在x,y平面中给定两个点: x, f(x) 1, 3 2, 5 我可以使用拉格朗日插值它们并找到f(1.5),结果是4。经过一点思考,我设法找到了一种方法来发现方程的系数: void l1Coefficients(const vector<double> &x, const vector<double> &y) { double a0 = y[0]/(x[0]-x[1]); double a1 = y[1]/(x[1]-x[0]);

x,y
平面中给定两个点:

x, f(x)
1, 3
2, 5
我可以使用拉格朗日插值它们并找到
f(1.5)
,结果是
4
。经过一点思考,我设法找到了一种方法来发现方程的系数:

void l1Coefficients(const vector<double> &x, const vector<double> &y) {

    double a0 = y[0]/(x[0]-x[1]);
    double a1 = y[1]/(x[1]-x[0]);

    double b0 = (-x[1]*y[0])/(x[0]-x[1]);
    double b1 = (-x[0]*y[1])/(x[1]-x[0]);

    double a = a0 + a1;
    double b = b0 + b1;

    cout << "P1(x) = " << a << "x +" << b << endl;
}
我发现等式
P2(x)=1x^2+0x+0
具有以下内容:

void l2Coefficients(const vector<double> &x, const vector<double> &y) {

    double a0 =              y[0] / ((x[0]-x[1])*(x[0]-x[2]));
    double a1 =              y[1] / ((x[1]-x[0])*(x[1]-x[2]));
    double a2 =              y[2] / ((x[2]-x[0])*(x[2]-x[1]));

    double b0 = -(x[1]+x[2])*y[0] / ((x[0]-x[1])*(x[0]-x[2]));
    double b1 = -(x[0]+x[2])*y[1] / ((x[1]-x[0])*(x[1]-x[2]));
    double b2 = -(x[0]+x[1])*y[2] / ((x[2]-x[0])*(x[2]-x[1]));

    double c0 =  (x[1]*x[2])*y[0] / ((x[0]-x[1])*(x[0]-x[2]));
    double c1 =  (x[0]*x[2])*y[1] / ((x[1]-x[0])*(x[1]-x[2]));
    double c2 =  (x[0]*x[1])*y[2] / ((x[2]-x[0])*(x[2]-x[1]));

    double a = a0 + a1 + a2;
    double b = b0 + b1 + b2;
    double c = c0 + c1 + c2;

    cout << "P2(x) = " << a << "x^2 +" << b << "x +" << c << endl;
}

这是一个简单的线性代数问题

我们有一组形式为xk->f(xk)的N个样本,我们知道函数f(x)的一般形式,即:

f(x)=c0x0+c1x1+…+cN-1xN-1

我们想找到系数c0。。。cN-1。为了实现这一点,我们建立了一个由N个方程组成的系统,其形式如下:

c0xk0+c1xk1+…+cN-1xkN-1=f(xk)

其中k是样本编号。因为xk和f(xk)是常数而不是变量,所以我们有一个线性方程组

用线性代数表示,我们必须解决:

Ac=b

其中A是x的幂的A,b是f(xk)值的向量

要解决这样一个系统,您需要一个线性代数库,例如
Eigen
。参见示例代码

这种方法唯一可能出错的是线性方程组的确定不足,如果你的N个样本可以用一个小于N-1次的多项式拟合,就会出现这种情况。在这种情况下,您仍然可以使用Moore-Penrose伪逆解此系统,如下所示:

c=品脱伏特(A)*b


不幸的是,
Eigen
没有
pinv()
实现,尽管用奇异值分解(SVD)自己编写代码非常容易。

我创建了一个矩阵解决方案的简单实现:

#include <iostream>
#include <vector>
#include <stdexcept>

class Matrix
{

private:

    class RowIterator
    {
    public:
        RowIterator(Matrix* mat, int rowNum) :_mat(mat), _rowNum(rowNum) {}
        double& operator[] (int colNum) { return _mat->_data[_rowNum*_mat->_sizeX + colNum]; }
    private:
        Matrix* _mat;
        int _rowNum;
    };

    int _sizeY, _sizeX;
    std::vector<double> _data;

public:

    Matrix(int sizeY, int sizeX) : _sizeY(sizeY), _sizeX(sizeX), _data(_sizeY*_sizeX){}
    Matrix(std::vector<std::vector<double> > initList) : _sizeY(initList.size()), _sizeX(_sizeY>0 ? initList.begin()->size() : 0), _data()
    { 
        _data.reserve(_sizeY*_sizeX);
        for (const std::vector<double>& list : initList)
        {
            _data.insert(_data.end(), list.begin(), list.end());
        }
    }

    RowIterator operator[] (int rowNum) { return RowIterator(this, rowNum); }

    int getSize() { return _sizeX*_sizeY; }
    int getSizeX() { return _sizeX; }
    int getSizeY() { return _sizeY; }

    Matrix reduce(int rowNum, int colNum)
    {
        Matrix mat(_sizeY-1, _sizeX-1);
        int rowRem = 0;
        for (int y = 0; y < _sizeY; y++)
        {
            if (rowNum == y)
            {
                rowRem = 1;
                continue;
            }
            int colRem = 0;
            for (int x = 0; x < _sizeX; x++)
            {
                if (colNum == x)
                {
                    colRem = 1;
                    continue;
                }
                mat[y - rowRem][x - colRem] = (*this)[y][x];
            }
        }
        return mat;
    }

    Matrix replaceCol(int colNum, std::vector<double> newCol)
    {
        Matrix mat = *this;
        for (int y = 0; y < _sizeY; y++)
        {
            mat[y][colNum] = newCol[y];
        }
        return mat;
    }

};

double solveMatrix(Matrix mat)
{
    if (mat.getSizeX() != mat.getSizeY()) throw std::invalid_argument("Not square matrix");
    if (mat.getSize() > 1)
    {
        double sum = 0.0;
        int sign = 1;
        for (int x = 0; x < mat.getSizeX(); x++)
        {
            sum += sign * mat[0][x] * solveMatrix(mat.reduce(0, x));
            sign = -sign;
        }
        return sum;
    }

    return mat[0][0];
}

std::vector<double> solveEq(std::vector< std::pair<double, double> > points)
{
    std::vector<std::vector<double> > xes(points.size());
    for (int i = 0; i<points.size(); i++)
    {
        xes[i].push_back(1);
        for (int j = 1; j<points.size(); j++)
        {
            xes[i].push_back(xes[i].back() * points[i].first);
        }
    }

    Matrix mat(xes);

    std::vector<double> ys(points.size());

    for (int i = 0; i < points.size(); i++)
    {
        ys[i] = points[i].second;
    }

    double w = solveMatrix(mat);

    std::vector<double> result(points.size(), 0.0);

    if(w!=0)
        for (int i = 0; i < ys.size(); i++)
        {
            result[i] = solveMatrix(mat.replaceCol(i, ys));
            result[i] /= w;
        }

    return result;
}

void printCoe(std::vector<double> coe)
{
    std::cout << "f(x)=";
    bool notFirstSign = false;
    for (int i = coe.size() - 1; i >= 0; i--)
    {
        if (coe[i] != 0.0)
        {
            if (coe[i] >= 0.0 && notFirstSign)
                std::cout << "+";
            notFirstSign = true;
            if (coe[i] != 1.0)
                if (coe[i] == -1.0)
                    std::cout << "-";
                else
                    std::cout << coe[i];
            if (i == 1)
                std::cout << "x";
            if (i>1)
                std::cout << "x^" << i;
        }
    }
    std::cout << std::endl;
}

int main()
{
    std::vector< std::pair<double, double> > points1 = { {3,31}, {6,94}, {4,48}, {0,4} };
    std::vector<double> coe = solveEq(points1);
    printCoe(coe);

    std::vector< std::pair<double, double> > points2 = { { 0,0 },{ 1,-1 },{ 2,-16 },{ 3,-81 },{ 4,-256 } };
    printCoe(solveEq(points2));

    printCoe(solveEq({ { 0,0 },{ 1,1 },{ 2,8 },{ 3,27 } }));

    std::cin.ignore();
    return 0;
}
#包括
#包括
#包括
类矩阵
{
私人:
类行迭代器
{
公众:
行迭代器(矩阵*mat,int-rowNum):_-mat(mat),_-rowNum(rowNum){
双精度&运算符[](int colNum){return_mat->_data[_rowNum*_mat->_sizeX+colNum];}
私人:
矩阵*矩阵;
int_rowNum;
};
国际标准;
std::vector_数据;
公众:
矩阵(int-sizeY,int-sizeX):\u-sizeY(sizeY),\u-sizeX(sizeX),\u-data(\u-sizeY*\u-sizeX){}
矩阵(std::vector initList):\u sizeY(initList.size()),\u sizeX(\u sizeY>0?initList.begin()->size():0),\u data()
{ 
_数据。储量(_sizeY*_sizeX);
for(const std::vector&list:initList)
{
_data.insert(_data.end(),list.begin(),list.end());
}
}
RowIterator运算符[](int rowNum){返回RowIterator(this,rowNum);}
int getSize(){return\u sizeX*\u sizeY;}
int getSizeX(){return\u sizeX;}
int getSizeY(){return\u sizeY;}
矩阵缩减(int rowNum,int colNum)
{
矩阵矩阵(_sizeY-1,_sizeX-1);
int-rowRem=0;
对于(int y=0;y<\u sizeY;y++)
{
如果(rowNum==y)
{
rowRem=1;
继续;
}
int colRem=0;
对于(int x=0;x<\u sizeX;x++)
{
if(colNum==x)
{
colRem=1;
继续;
}
mat[y-rowRem][x-colRem]=(*此)[y][x];
}
}
返回垫;
}
矩阵替换列(int colNum,std::vector newCol)
{
矩阵mat=*这个;
对于(int y=0;y<\u sizeY;y++)
{
mat[y][colNum]=newCol[y];
}
返回垫;
}
};
双矩阵(矩阵矩阵)
{
if(mat.getSizeX()!=mat.getSizeY())抛出std::无效的_参数(“非平方矩阵”);
如果(mat.getSize()>1)
{
双和=0.0;
int符号=1;
对于(int x=0;x点)
{
std::向量x(points.size());

例如(int i=0;iYou可能想看看:是的,我们的西班牙语很流利;)这篇演讲是用英语写的,有非常清楚的解释,虽然没有代码:嗯,我想我错过了代码。我投票将这个问题作为离题题来结束,因为这是一个数学问题,不是真正的计算机编程问题。你可能会在math.se上找到更多的帮助。@LutzL我不是建议使用SVD进行简单的线性求解,而是专门用于伪逆实现。虽然Wikipedia确实提到了这种方法,但它似乎仅限于满(行或列)秩非方矩阵A的情况。在我们的例子中,A是方的,但不一定是满秩的。因此,这是一种方法。
Pn(x) = c_2x^2 + c_1x^1 + c_0x^0 + ...
#include <iostream>
#include <vector>
#include <stdexcept>

class Matrix
{

private:

    class RowIterator
    {
    public:
        RowIterator(Matrix* mat, int rowNum) :_mat(mat), _rowNum(rowNum) {}
        double& operator[] (int colNum) { return _mat->_data[_rowNum*_mat->_sizeX + colNum]; }
    private:
        Matrix* _mat;
        int _rowNum;
    };

    int _sizeY, _sizeX;
    std::vector<double> _data;

public:

    Matrix(int sizeY, int sizeX) : _sizeY(sizeY), _sizeX(sizeX), _data(_sizeY*_sizeX){}
    Matrix(std::vector<std::vector<double> > initList) : _sizeY(initList.size()), _sizeX(_sizeY>0 ? initList.begin()->size() : 0), _data()
    { 
        _data.reserve(_sizeY*_sizeX);
        for (const std::vector<double>& list : initList)
        {
            _data.insert(_data.end(), list.begin(), list.end());
        }
    }

    RowIterator operator[] (int rowNum) { return RowIterator(this, rowNum); }

    int getSize() { return _sizeX*_sizeY; }
    int getSizeX() { return _sizeX; }
    int getSizeY() { return _sizeY; }

    Matrix reduce(int rowNum, int colNum)
    {
        Matrix mat(_sizeY-1, _sizeX-1);
        int rowRem = 0;
        for (int y = 0; y < _sizeY; y++)
        {
            if (rowNum == y)
            {
                rowRem = 1;
                continue;
            }
            int colRem = 0;
            for (int x = 0; x < _sizeX; x++)
            {
                if (colNum == x)
                {
                    colRem = 1;
                    continue;
                }
                mat[y - rowRem][x - colRem] = (*this)[y][x];
            }
        }
        return mat;
    }

    Matrix replaceCol(int colNum, std::vector<double> newCol)
    {
        Matrix mat = *this;
        for (int y = 0; y < _sizeY; y++)
        {
            mat[y][colNum] = newCol[y];
        }
        return mat;
    }

};

double solveMatrix(Matrix mat)
{
    if (mat.getSizeX() != mat.getSizeY()) throw std::invalid_argument("Not square matrix");
    if (mat.getSize() > 1)
    {
        double sum = 0.0;
        int sign = 1;
        for (int x = 0; x < mat.getSizeX(); x++)
        {
            sum += sign * mat[0][x] * solveMatrix(mat.reduce(0, x));
            sign = -sign;
        }
        return sum;
    }

    return mat[0][0];
}

std::vector<double> solveEq(std::vector< std::pair<double, double> > points)
{
    std::vector<std::vector<double> > xes(points.size());
    for (int i = 0; i<points.size(); i++)
    {
        xes[i].push_back(1);
        for (int j = 1; j<points.size(); j++)
        {
            xes[i].push_back(xes[i].back() * points[i].first);
        }
    }

    Matrix mat(xes);

    std::vector<double> ys(points.size());

    for (int i = 0; i < points.size(); i++)
    {
        ys[i] = points[i].second;
    }

    double w = solveMatrix(mat);

    std::vector<double> result(points.size(), 0.0);

    if(w!=0)
        for (int i = 0; i < ys.size(); i++)
        {
            result[i] = solveMatrix(mat.replaceCol(i, ys));
            result[i] /= w;
        }

    return result;
}

void printCoe(std::vector<double> coe)
{
    std::cout << "f(x)=";
    bool notFirstSign = false;
    for (int i = coe.size() - 1; i >= 0; i--)
    {
        if (coe[i] != 0.0)
        {
            if (coe[i] >= 0.0 && notFirstSign)
                std::cout << "+";
            notFirstSign = true;
            if (coe[i] != 1.0)
                if (coe[i] == -1.0)
                    std::cout << "-";
                else
                    std::cout << coe[i];
            if (i == 1)
                std::cout << "x";
            if (i>1)
                std::cout << "x^" << i;
        }
    }
    std::cout << std::endl;
}

int main()
{
    std::vector< std::pair<double, double> > points1 = { {3,31}, {6,94}, {4,48}, {0,4} };
    std::vector<double> coe = solveEq(points1);
    printCoe(coe);

    std::vector< std::pair<double, double> > points2 = { { 0,0 },{ 1,-1 },{ 2,-16 },{ 3,-81 },{ 4,-256 } };
    printCoe(solveEq(points2));

    printCoe(solveEq({ { 0,0 },{ 1,1 },{ 2,8 },{ 3,27 } }));

    std::cin.ignore();
    return 0;
}