21xrx.com
2025-03-29 18:18:41 Saturday
文章检索 我的文章 写文章
C++三次样条插值实现
2023-06-30 08:38:25 深夜i     57     0
C++ 三次样条 插值 实现

C++三次样条插值是一种常用的数据插值方法,主要用于在给定的节点上通过插值函数,得到数据的平滑曲线,从而减小数据的波动性,适用于各种数据场景下的插值。

具体实现过程如下:

1. 根据插值节点计算出节点间距离和节点之间的相邻斜率

2. 构建三对角矩阵,并解出矩阵方程组

3. 根据解得的系数,计算出每个插值节点上的插值函数和拟合曲线

下面是一个简单的C++实现示例:

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
//定义节点结构体,包括x值和y值
struct Point y;
;
//计算相邻两个节点间的斜率
vector<double> calcSlope(vector<Point>& points) {
  int n = points.size();
  vector<double> slope(n + 1, 0);
  for (int i = 1; i < n; ++i) {
    slope[i] = (points[i].y - points[i - 1].y) / (points[i].x - points[i - 1].x);
  }
  slope[n] = slope[n - 1];
  return slope;
}
//构建三对角矩阵
void buildMatrix(vector<Point>& points, vector<double>& slope, vector<double>& A, vector<double>& B, vector<double>& C, vector<double>& F) {
  int n = points.size() - 1;
  double h1, h2, a, b, c, f;
  for (int i = 1; i < n; ++i) {
    h1 = points[i].x - points[i - 1].x;
    h2 = points[i + 1].x - points[i].x;
    a = h1 / (h1 + h2);
    b = 2;
    c = h2 / (h1 + h2);
    f = 6 * (slope[i + 1] - slope[i]) / (points[i + 1].x - points[i - 1].x);
    A.push_back(a);
    B.push_back(b);
    C.push_back(c);
    F.push_back(f);
  }
}
//解三对角方程组
void tridiagonalSolve(vector<double>& A, vector<double>& B, vector<double>& C, vector<double>& F, vector<double>& result) {
  int n = A.size();
  vector<double> alpha(n), beta(n);
  alpha[1] = B[0];
  for (int i = 1; i < n; ++i) {
    beta[i] = C[i - 1] / alpha[i];
    alpha[i + 1] = B[i] - A[i] * beta[i];
  }
  vector<double> gamma(n);
  gamma[1] = F[0] / alpha[1];
  for (int i = 1; i < n; ++i) {
    gamma[i + 1] = (F[i] - A[i] * gamma[i]) / alpha[i + 1];
  }
  result[n] = gamma[n];
  for (int i = n - 1; i >= 1; --i) {
    result[i] = gamma[i] - beta[i] * result[i + 1];
  }
}
//计算每个节点上的拟合函数
void calcFunc(vector<Point>& points, vector<double>& slope, vector<double>& coeffs, vector<double>& func) {
  int n = points.size() - 1;
  double h, a, b, c, d;
  for (int i = 0; i < n; ++i) {
    h = points[i + 1].x - points[i].x;
    a = (coeffs[i + 1] - coeffs[i]) / (6 * h);
    b = coeffs[i] / 2;
    c = (slope[i + 1] - slope[i]) / h - h * (2 * coeffs[i] + coeffs[i + 1]) / 6;
    d = points[i].y;
    for (double x = points[i].x; x <= points[i + 1].x; x += 0.1) {
      double y = a * pow(x - points[i].x, 3) + b * pow(x - points[i].x, 2) + c * (x - points[i].x) + d;
      func.push_back(y);
    }
  }
}
int main() {
  vector<Point> points = { 1, 1, 1, 3, 2}; //插值节点
  vector<double> slope = calcSlope(points);
  vector<double> A, B, C, F, coeffs(points.size());
  buildMatrix(points, slope, A, B, C, F);
  tridiagonalSolve(A, B, C, F, coeffs);
  vector<double> func;
  calcFunc(points, slope, coeffs, func);
  for (double y : func)
    cout << y << " ";
  
  return 0;
}

通过上述代码,可以得到给定插值节点的拟合曲线,波动性较小,可以更加直观地表示数据特点,提高数据的可读性和可靠性。

  
  

评论区

请求出错了