提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章
目录
文章目录
前言
一、核心算法原理
二、 C++ 完整代码
三、运行结果
总结
前言
基于C++编写了一套完整的代码。这套代码不仅实现了牛顿前插公式和牛顿后插公式,还特别针对特殊要求,实现了:
差分表的格式化打印(与教材表格一致)。
GeoGebra友好的插值公式打印(输出以 xx 为自变量的多项式代数式,可直接复制粘贴到GeoGebra)。
例5的完整计算与误差估计(采用书中给定的数据和4次牛顿前插公式)。
例题资料如下图:
提示:以下是本篇文章正文内容,下面案例可供参考
一、核心算法原理
1.前插公式(以 x0 为基准,t=(x−x0/h):
2.后插公式(以 xn 为基准,t=(x−xn)/h):
二、 C++ 完整代码
#include <iostream> #include <vector> #include <iomanip> #include <cmath> #include <string> #include <sstream> using namespace std; // 计算阶乘 double factorial(int n) { double res = 1.0; for (int i = 2; i <= n; ++i) res *= i; return res; } //牛顿插值 class NewtonInterpolator { private: vector<double> x_data;//x值 vector<double> y_data;//y值 vector<vector<double>> diff_table; // 差分表 int n; double h; // 步长 public: NewtonInterpolator(const vector<double>& x, const vector<double>& y) : x_data(x), y_data(y), n(x.size()) { // 自动计算步长 (假设等距) h = x_data[1] - x_data[0]; buildDifferenceTable();//构建差分表 } // 1. 构建差分表 void buildDifferenceTable() { diff_table.assign(n, vector<double>(n, 0.0)); // 0阶差分即函数值本身 for (int i = 0; i < n; ++i) { diff_table[i][0] = y_data[i];//i行0列是函数值 } // 递推计算高阶差分 for (int j = 1; j < n; ++j) { //j=1:一阶差分 for (int i = 0; i < n - j; ++i) { diff_table[i][j] = diff_table[i + 1][j - 1] - diff_table[i][j - 1];//求j阶差分 } } } // 2. 打印差分表 void printDifferenceTable() const { cout << "================ 差分表 ================" << endl; cout << setw(8) << "xk" << setw(12) << "f(xk)" << setw(12) << "Δf" << setw(12) << "Δ^2f" << setw(12) << "Δ^3f" << setw(12) << "Δ^4f" << setw(12) << "Δ^5f" << endl; for (int i = 0; i < n; ++i) { cout << setw(8) << fixed << setprecision(2) << x_data[i]; for (int j = 0; j < n - i; ++j) { cout << setw(12) << fixed << setprecision(5) << diff_table[i][j]; } cout << endl; } cout << "=========================================" << endl << endl; } // 3. 打印适用于 GeoGebra 的前插公式 void printForwardFormula() const { cout << "【牛顿前插公式】(可直接复制到 GeoGebra 绘图):" << endl; cout << "f(x) = "; for (int i = 0; i < n; ++i) { double coef = diff_table[0][i] / (factorial(i) * pow(h, i)); if (i > 0) { if (coef >= 0) cout << " + "; else { cout << " - "; coef = -coef; } } else { if (coef < 0) { cout << "-"; coef = -coef; } } cout << fixed << setprecision(5) << coef; for (int j = 0; j < i; ++j) { cout << "(x - " << fixed << setprecision(2) << x_data[j] << ")"; } } cout << endl << endl; } // 4. 打印适用于 GeoGebra 的后插公式 void printBackwardFormula() const { cout << "【牛顿后插公式】(可直接复制到 GeoGebra 绘图):" << endl; cout << "g(x) = "; for (int i = 0; i < n; ++i) { // 后插公式的差分取自差分表底部的对角线 double coef = diff_table[n - 1 - i][i] / (factorial(i) * pow(h, i)); if (i > 0) { if (coef >= 0) cout << " + "; else { cout << " - "; coef = -coef; } } else { if (coef < 0) { cout << "-"; coef = -coef; } } cout << fixed << setprecision(5) << coef; for (int j = 0; j < i; ++j) { cout << "(x - " << fixed << setprecision(2) << x_data[n - 1 - j] << ")"; } } cout << endl << endl; } // 5. 牛顿前插公式求值 double solveForward(double target_x) const { double t = (target_x - x_data[0]) / h; double result = diff_table[0][0]; double term = 1.0; for (int i = 1; i < n; ++i) { term *= (t - (i - 1));//二项式展开系数的分子,分母是阶乘 result += (diff_table[0][i] / factorial(i)) * term; } return result; } // 6. 牛顿后插公式求值 double solveBackward(double target_x) const { double t = (target_x - x_data[n - 1]) / h; double result = diff_table[n - 1][0]; double term = 1.0; for (int i = 1; i < n; ++i) { term *= (t + (i - 1)); result += (diff_table[n - 1 - i][i] / factorial(i)) * term; } return result; } }; int main() { // 输入例5的数据:f(x) = cos(x), x_k = k*h, h=0.1, k=0..5 vector<double> x = { 0.00, 0.10, 0.20, 0.30, 0.40, 0.50 }; vector<double> y = { 1.00000, 0.99500, 0.98007, 0.95534, 0.92106, 0.87758 }; double target_x = 0.048; cout << "========== 牛顿插值法计算例5 ==========" << endl; cout << "已知节点 x_k = k*0.1, 求 f(0.048)" << endl << endl; NewtonInterpolator newton(x, y); // 打印差分表 newton.printDifferenceTable(); // 打印可用于 GeoGebra 的公式 newton.printForwardFormula(); newton.printBackwardFormula(); // 计算并输出结果 double result_fwd = newton.solveForward(target_x); double result_bwd = newton.solveBackward(target_x); cout << "【计算结果】" << endl; cout << "牛顿前插公式计算 f(0.048) ≈ " << fixed << setprecision(6) << result_fwd << endl; cout << "牛顿后插公式计算 f(0.048) ≈ " << fixed << setprecision(6) << result_bwd << endl; cout << "真实值 cos(0.048) ≈ " << fixed << setprecision(6) << cos(target_x) << endl; // 误差估计(使用书中公式 3.14) double t = (target_x - x[0]) / 0.1; double M5 = sin(0.5); // M5 = max|f^(5)(x)| = max|sin(x)| 在 [0, 0.5] 上 double error_bound = (M5 / factorial(5)) * abs(t * (t - 1) * (t - 2) * (t - 3) * (t - 4)) * pow(0.1, 5);//求余项 cout << "\n【误差估计】(使用 4 次前插公式)" << endl; cout << "余项 |R_4(0.048)| <= " << scientific << setprecision(4) << error_bound << endl; return 0; }三、运行结果
========== 牛顿插值法计算例5 ==========
已知节点 x_k = k*0.1, 求 f(0.048)
================ 差分表 ================
xk f(xk) Δf Δ^2f Δ^3f Δ^4f Δ^5f
0.00 1.00000 -0.00500 -0.00993 0.00013 0.00012 -0.00002
0.10 0.99500 -0.01493 -0.00980 0.00025 0.00010
0.20 0.98007 -0.02473 -0.00955 0.00035
0.30 0.95534 -0.03428 -0.00920
0.40 0.92106 -0.04348
0.50 0.87758
=========================================
【牛顿前插公式】(可直接复制到 GeoGebra 绘图):
f(x) = 1.00000 - 0.05000(x - 0.00) - 0.49650(x - 0.00)(x - 0.10) + 0.02167(x - 0.00)(x - 0.10)(x - 0.20) + 0.05000(x - 0.00)(x - 0.10)(x - 0.20)(x - 0.30) - 0.01667(x - 0.00)(x - 0.10)(x - 0.20)(x - 0.30)(x - 0.40)
【牛顿后插公式】(可直接复制到 GeoGebra 绘图):
g(x) = 0.87758 - 0.43480(x - 0.50) - 0.46000(x - 0.50)(x - 0.40) + 0.05833(x - 0.50)(x - 0.40)(x - 0.30) + 0.04167(x - 0.50)(x - 0.40)(x - 0.30)(x - 0.20) - 0.01667(x - 0.50)(x - 0.40)(x - 0.30)(x - 0.20)(x - 0.10)
【计算结果】
牛顿前插公式计算 f(0.048) ≈ 0.998842
牛顿后插公式计算 f(0.048) ≈ 0.998842
真实值 cos(0.048) ≈ 0.998848
【误差估计】(使用 4 次前插公式)
余项 |R_4(0.048)| <= 1.3445e-07
总结
1.前插与后插的等价性:
前插公式和后插公式打印出来的多项式看起来完全不一样(因为基准点不同,展开的多项式系数不同),但它们在数学上是完全等价的。在 x=0.048 处计算的结果均为0.998843,这也印证了牛顿插值多项式的唯一性。
2.误差估计:
代码严格遵守了教材中式 (3.14) 的余项公式:
其中。程序算出的误差上限为 1.3445e-07,与教材十分接近。
3.图形计算器 - GeoGebra,可以把公式复制进去查看曲线。