我需要建立三次样条插值曲线,给出空间中的点。
我有下一个代码。这很好,但没有必要的精度(这很可能是逻辑错误)。
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
struct INPUT {
int N;
std::vector<double> x;
int M;
std::vector<std::vector<double> > lattice;
int K;
std::vector<double> res_lattice;
} input_data;
class CubicSpline{
double a = 0;
double b = 0;
double c = 0;
double d = 0;
double x = 0;
public:
CubicSpline() {}
double get(double input_x){
double f_x = input_x-x;
return a + b*f_x + c*f_x*f_x/2 + d*f_x*f_x*f_x/6;
}
void setA(double new_a) {
a = new_a;
}
void setX(double new_x) {
x = new_x;
}
void setB(double new_b) {
b = new_b;
}
void setC(double new_c) {
c = new_c;
}
void setD(double new_d) {
d = new_d;
}
};
class CubicSplineCurve{
std::vector<double> x_values;
std::vector<double> y_values;
int N;
std::vector<CubicSpline> splines;
public:
CubicSplineCurve(std::vector<double> x_values, std::vector<double> y_values, int N) : x_values(x_values), y_values(y_values), N(N) {
splines = std::vector<CubicSpline>(N);
int i;
for (i = 1; i < N; i++){
splines[i].setA(y_values[i]);
splines[i].setX(x_values[i]);
}
// std::vector<double> c_values(*get_c_values());
// std::vector<double> c_values(N);
// get_c_values(c_values);
std::vector<double> c_values = get_c_values();
for (i = 1; i < N; i++){
splines[i].setC(c_values[i]);
}
std::vector<double> d_values(N);
d_values[1] = c_values[1]/h(1);
for (i = 2; i < N; i++){
d_values[i] = (c_values[i] - c_values[i-1])/h(i);
splines[i].setD(d_values[i]);
}
for (i = 1; i < N; i++){
// splines[i].setB(u(i) + c_values[i]*h(i)/2 - d_values[i]*pow(h(i), 2)/6);
splines[i].setB(h(i)*(2*c_values[i] + c_values[i-1])/6 + u(i));
}
}
double get(double x){
int i;
for (i = 1; i < N; i++){
if (x <= x_values[i]){
return splines[i].get(x);
}
}
}
private:
std::vector<double> get_c_values(){
std::vector<double> c_values(N);
c_values[0] = 0;
c_values[N-1] = 0;
int k, i;
std::vector<std::vector<double> > c_matrix = std::vector<std::vector<double> >(N-2);
for (i = 0; i < N-2; i++){
c_matrix[i] = std::vector<double>(N-2);
}
int n = N-3;
c_matrix[0][0] = 2;
c_matrix[0][1] = h(2)/(h(1) + h(2));
c_matrix[n][n] = 2;
c_matrix[n][n-1] = h(N-2)/(h(N-2) + h(N-1));
for (i = 1; i < n; i++){
c_matrix[i][i-1] = h(i)/(h(i) + h(i+1));
c_matrix[i][i] = 2;
c_matrix[i][i+1] = h(i+1)/(h(i) + h(i+1));
}
std::vector<double> res_vector(N-2);
for (i = 0;i < n; i++){
res_vector[i] = 6 * triple_u(i+2);
}
// std::vector<double> valuable_c_values_gauss = gauss_for_tridiagonal_matrix(c_matrix, res_vector, N-2);
std::vector<double> valuable_c_values = shuttle(c_matrix, res_vector, N-2);
for (i = 1; i < N-1; i++){
c_values[i] = valuable_c_values[i-1];
}
// return new std::vector<double>(c_values);
return c_values;
}
// Here i try to round near 0 values, and get rid of computational error.
double h(int i){
return round((x_values[i] - x_values[i-1])*10000000000)/10000000000;
}
double u(int i){
return round((y_values[i]-y_values[i-1])*1000000000/h(i))/1000000000;
}
double triple_u(int i){
return round((u(i) - u(i-1))*1000000000/(x_values[i]-x_values[i-2]))/1000000000;
}
// Next 2 methods solving SLE, they gives the same results, for now i use shutle method.
std::vector<double> gauss_for_tridiagonal_matrix(std::vector<std::vector<double> > tridiagonalMatrix, std::vector<double> res_vector, int N){
int i;
int k;
for (i = 0; i < N-1; i++){
double factor = tridiagonalMatrix[i+1][i]/tridiagonalMatrix[i][i];
tridiagonalMatrix[i+1][i] = 0;
for (k = i + 1; k < N; k++){
tridiagonalMatrix[i+1][k] -= tridiagonalMatrix[i][k]*factor;
}
res_vector[i+1] -= res_vector[i]*factor;
}
for (i = N-1; i > 0; i--){
double factor = tridiagonalMatrix[i][i];
tridiagonalMatrix[i][i] = 1;
res_vector[i] = res_vector[i]/factor;
factor = tridiagonalMatrix[i-1][i]/tridiagonalMatrix[i][i];
for (k = i; k > 0; k--){
tridiagonalMatrix[i-1][k] -= tridiagonalMatrix[i][k]*factor;
}
res_vector[i-1] -= res_vector[i]*factor;
}
double factor = tridiagonalMatrix[0][0];
res_vector[0] = res_vector[0]/factor;
return res_vector;
}
// I get it in internet, because have no clear understanding of this method yet.
std::vector<double> shuttle(std::vector<std::vector<double> > tridiagonalMatrix, std::vector<double> res_vector, int N){
double y;
std::vector<double> a(N);
std::vector<double> B(N);
int N1 = N - 1;
y = tridiagonalMatrix[0][0];
a[0] = -tridiagonalMatrix[0][1] / y;
B[0] = res_vector[0] / y ;
for (int i = 1; i < N1; i++) {
y = tridiagonalMatrix[i][i] + tridiagonalMatrix[i][i - 1] * a[i - 1];
a[i] = -tridiagonalMatrix[i][i + 1] / y;
B[i] = (res_vector[i] - tridiagonalMatrix[i][i - 1] * B[i - 1]) / y;
}
res_vector[N1] = (res_vector[N1] - tridiagonalMatrix[N1][N1 - 1] * B[N1 - 1]) / (tridiagonalMatrix[N1][N1] + tridiagonalMatrix[N1][N1 - 1] * a[N1 - 1]);
for (int i = N1 - 1; i >= 0; i--) {
res_vector[i] = a[i] * res_vector[i + 1] + B[i];
}
return res_vector;
}
};
void proceed_input(INPUT input){
int i,k;
std::vector<CubicSplineCurve> curves;
for (i = 0; i < input.M; i++){
curves.push_back(CubicSplineCurve(input.x, input.lattice[i], input.N));
}
double result;
cout.precision(8);
// for (i = 0; i < input.N; i++){
// double first = input.lattice[0][i];
// double second = curves[0].get(input.x[i]);
// cout << first << " " << second << " " << abs(first - second) << endl;
// }
for (i = 0; i < input.M; i++){
for (k = 0; k < input.K; k++){
result = curves[i].get(input.res_lattice[k]);
cout << result << " ";
}
cout << endl;
}
}
int main() {
cin >> input_data.N;
// input_data.x = std::vector<double>(input_data.N);
input_data.x = std::vector<double>(input_data.N);
int i;
for (i = 0; i < input_data.N; i++){
cin >> input_data.x[i];
}
cin >> input_data.M;
input_data.lattice = std::vector<std::vector<double> >(input_data.M);
int k;
for (k = 0; k < input_data.M; k++){
input_data.lattice[k] = std::vector<double>(input_data.N);
for (i = 0; i < input_data.N; i++){
cin >> input_data.lattice[k][i];
}
}
cin >> input_data.K;
input_data.res_lattice = std::vector<double>(input_data.K);
for (i = 0; i < input_data.K; i++){
cin >> input_data.res_lattice[i];
}
proceed_input(input_data);
return 0;
}
在这里我们可以看到,即使函数是连续的,它们的1阶和2阶导数也不等于它。但我无法理解为什么会这样。
哪里可能有错误?