🐱 算神的小窝 🤓

C#多项式拟合算法实现.md


CreationTime:5/7/2026 12:29:40 PM LastAccessTime:5/18/2026 3:27:18 AM


C#多项式拟合算法实现

以下是一个完整的 C# 多项式曲线拟合实现,采用最小二乘法构建正规方程,并使用列主元高斯消元法求解线性方程组。代码不依赖任何第三方库。

using System;

public static class PolynomialFitter
{
    /// <summary>
    /// 对给定数据点进行多项式拟合,返回从低次到高次排列的系数。
    /// </summary>
    /// <param name="x">自变量数组</param>
    /// <param name="y">因变量数组</param>
    /// <param name="degree">多项式阶数(必须 >= 0)</param>
    /// <returns>系数数组 [a0, a1, a2, ..., an],对应 a0 + a1*x + a2*x^2 + ...</returns>
    public static double[] Fit(double[] x, double[] y, int degree)
    {
        if (x == null) throw new ArgumentNullException(nameof(x));
        if (y == null) throw new ArgumentNullException(nameof(y));
        if (x.Length != y.Length) throw new ArgumentException("x 和 y 长度必须相同");
        if (degree < 0) throw new ArgumentException("阶数不能为负数");
        if (x.Length < degree + 1) throw new ArgumentException("数据点数必须大于等于阶数+1");

        int n = degree + 1;                     // 未知数个数
        double[,] normalMatrix = new double[n, n];
        double[] normalVector = new double[n];

        // 构建立方程 A^T A a = A^T y
        // 矩阵元素 (i, j) = Σ x_k^(i+j)
        // 右端向量 (i) = Σ y_k * x_k^i
        for (int k = 0; k < x.Length; k++)
        {
            double xi = x[k];
            double yi = y[k];
            double pow = 1.0;

            // 利用递推填充下三角部分,同时累积上三角
            for (int i = 0; i < n; i++)
            {
                normalVector[i] += yi * pow;
                double rowPow = pow;
                for (int j = i; j < n; j++)
                {
                    normalMatrix[i, j] += rowPow;
                    rowPow *= xi;
                }
                pow *= xi;
            }
        }

        // 对称填充下三角
        for (int i = 1; i < n; i++)
            for (int j = 0; j < i; j++)
                normalMatrix[i, j] = normalMatrix[j, i];

        return SolveLinearSystem(normalMatrix, normalVector);
    }

    /// <summary>
    /// 计算多项式在指定 x 处的值。
    /// </summary>
    public static double Predict(double x, double[] coefficients)
    {
        double result = 0.0;
        double pow = 1.0;
        for (int i = 0; i < coefficients.Length; i++)
        {
            result += coefficients[i] * pow;
            pow *= x;
        }
        return result;
    }

    /// <summary>
    /// 使用列主元高斯消元法求解线性方程组 A·x = b
    /// </summary>
    private static double[] SolveLinearSystem(double[,] A, double[] b)
    {
        int n = b.Length;
        double[,] mat = (double[,])A.Clone();
        double[] vec = (double[])b.Clone();

        // 消元过程
        for (int col = 0; col < n; col++)
        {
            // 查找主元
            int maxRow = col;
            double maxVal = Math.Abs(mat[col, col]);
            for (int row = col + 1; row < n; row++)
            {
                double absVal = Math.Abs(mat[row, col]);
                if (absVal > maxVal)
                {
                    maxVal = absVal;
                    maxRow = row;
                }
            }

            if (maxVal < 1e-12)
                throw new InvalidOperationException("正规方程奇异,无法求解。");

            // 交换当前行与最大主元行
            if (maxRow != col)
            {
                for (int j = col; j < n; j++)
                {
                    double tmp = mat[col, j];
                    mat[col, j] = mat[maxRow, j];
                    mat[maxRow, j] = tmp;
                }
                double tmpB = vec[col];
                vec[col] = vec[maxRow];
                vec[maxRow] = tmpB;
            }

            // 消去下方行
            for (int row = col + 1; row < n; row++)
            {
                double factor = mat[row, col] / mat[col, col];
                for (int j = col; j < n; j++)
                    mat[row, j] -= factor * mat[col, j];
                vec[row] -= factor * vec[col];
            }
        }

        // 回代过程
        double[] solution = new double[n];
        for (int row = n - 1; row >= 0; row--)
        {
            double sum = vec[row];
            for (int j = row + 1; j < n; j++)
                sum -= mat[row, j] * solution[j];
            solution[row] = sum / mat[row, row];
        }
        return solution;
    }
}

使用示例

double[] x = { 1, 2, 3, 4, 5 };
double[] y = { 2.1, 3.9, 6.1, 8.2, 9.8 };

// 拟合二次多项式 y = a0 + a1*x + a2*x^2
double[] coeff = PolynomialFitter.Fit(x, y, degree: 2);
Console.WriteLine(string.Join(", ", coeff));  // 输出: a0, a1, a2

// 预测 x = 6 处的值
double predicted = PolynomialFitter.Predict(6, coeff);
Console.WriteLine($"x=6, y≈{predicted:F3}");

算法说明

  1. 构建正规方程:对于 m 个数据点 (xₖ, yₖ) 和 n 阶多项式,正规方程矩阵 A(n+1 行 × n+1 列)的元素为 Σ xₖ^(i+j),右端向量为 Σ yₖ·xₖ^i(i, j 从 0 到 n)。
  2. 对称性优化:只计算矩阵上三角,最后复制到下三角以减少计算量。
  3. 求解线性方程组:采用列主元高斯消元法保证数值稳定性,当矩阵病态时抛出异常。
  4. 系数解释:返回的数组索引对应幂次,即 coeff[0] 是常数项,coeff[1] 是一次项系数,依此类推。

此实现可直接用于 WinForm、WPF 或控制台程序的数值分析场景。

An unhandled error has occurred. Reload 🗙