【数值计算方法】学习笔记

您所在的位置:网站首页 切线方程计算方法有哪些 【数值计算方法】学习笔记

【数值计算方法】学习笔记

2024-06-01 08:50| 来源: 网络整理| 查看: 265

写在最前面

本篇博文是作者当时期末备考期间总结的,里面包含了所有的重点知识以及作业代码。如果有同校同系的学弟学妹们也在看这篇文章,请把本文当做一个参考即可,大家不要直接搬运作业代码,毕竟亲力亲为才能增长能力呀。

前言

本学期作者需要学一门很重要的专业必修课——数值计算方法。

在这里插入图片描述

但是,宛如天书的教材、晦涩难懂的PPT、形态各异的公式…这些都不禁让人失去学习动力。几节课下来,深感自己学的不扎实,故需要结合具体题目和代码进行总结与复盘。本篇文章主要记录和整理了我在学习计算方法这门课中学习到的概念、公式、例题,以及用Python编写的相关算法代码。

文章目录 写在最前面前言一.误差1.误差与误差限1.1 误差的分类1.2 绝对误差与绝对误差限1.3 相对误差与相对误差限1.4 有效数字 2.数值计算需要遵循的原则 二.插值与拟合1.Lagrange插值1.1 一阶线性Lagrange插值1.2 二阶抛物Lagrange插值1.3 n阶Lagrange插值公式 2.Newton插值3.Hermite插值4.分段插值与样条插值5.插值余项与误差估计6.曲线拟合 三.数值微积分1.梯形公式与中矩形公式2.Simpson公式3.Cotes公式4.复化求积公式4.1 复化梯形公式4.2 复化Simpson公式4.3 复化Cotes公式 5.变步长梯形公式6.Romberg公式7.Gauss求积公式7.1 Gauss-Legendre求积公式7.2 Gauss-Chebyshev求积公式 8.数值微分8.1 两点公式8.2 三点公式 四.非线性方程1.二分法2.迭代法3.Newton迭代法4.弦截法4.1 单点弦截法4.2 两点弦截法

一.误差 1.误差与误差限 1.1 误差的分类

数值计算方法不研究模型误差和观测误差,其主要研究方法误差(截断误差)和舍入误差。

模型误差:在将实际问题转化为数学模型的过程中,为了使数学模型尽量简单,以便于分析或计算,往往要忽略一些次要的因素,进行合理的简化。这样,实际问题与数学模型之间就产生了误差,这种误差称为模型误差,计算方法课中不讨论此种误差。

观测误差:由于仪器本身的精度有限或某些偶然的客观因素会引入一定的误差,这种误差叫做观测误差,计算方法课中不讨论此种误差。

方法误差:当实际问题的数学模型很复杂,不能获取模型的精确解,必须提供近似解,模型的准确解与数值方法准确解之差称为截断误差或方法误差。

舍入误差:用有限位小数来代替无穷小数或用位数较少的小数来代替位数较多的有限小数所产生的误差。

1.2 绝对误差与绝对误差限

绝对误差(误差):绝对误差简称误差。设x是准确值,x*为x的一个近似值,则近似值x的绝对误差为e(x)。

在这里插入图片描述 绝对误差限:绝对误差的绝对值不超过某个正数ε,即|x-x*|≤ε,x落在[x-ε,x+ε]范围内。这个正数ε就是绝对误差限。

在这里插入图片描述

1.3 相对误差与相对误差限

相对误差:设x为准确值,x是近似值,e是近似值的绝对误差,则ε/x为该近似值的相对误差,记作er*。

在这里插入图片描述

相对误差限:相对误差的值不超过某个正数,即|(x-x*)/x|≤εr,这个正数εr就是相对误差限。

在这里插入图片描述

1.4 有效数字

如果x*近似表示x准确到小数后第n位,并从x *第n位起直到最左边的非零数字之间的一切数字都称为有效数字,并把有效数字的位数称为有效位数。

在这里插入图片描述

规格化形式:

在这里插入图片描述 有效数字与绝对误差的关系: 在这里插入图片描述

有效数字与相对误差的关系:

在这里插入图片描述

2.数值计算需要遵循的原则

i. 要使用数值稳定的算法,防止出现病态问题。

ii. 避免两个相似数相减,需进行等价变换。

iii. 绝对值太小的数不适合作为除数。

iv. 避免大数吃小数的现象。

v. 先化简再进行计算,避免误差的持续积累。

vi. 可以利用算法的递推性,简化结构并节省计算量。

 

二.插值与拟合

在这里插入图片描述

1.Lagrange插值

Lagrange插值公式的基本思想是把Pn(x)的构造问题转化为n+1个插值基函数li(x)(i=0,1,…,n)的构造。基函数构造完成后便可构造一个次数不超过n的插值多项式,并使之满足条件Pn(xi)=yi(i=0,1,2…)。

在这里插入图片描述 在这里插入图片描述  

1.1 一阶线性Lagrange插值

在这里插入图片描述 一阶Lagrange插值称为一次线性Lagrange插值。其线性插值基函数和一次插值函数表达式分别为:

在这里插入图片描述 在这里插入图片描述  

1.2 二阶抛物Lagrange插值

在这里插入图片描述

二阶Lagrange插值称为二次抛物Lagrange插值。其插值基函数和插值函数表达式分别为: 在这里插入图片描述 在这里插入图片描述

【例题】

在这里插入图片描述 【代码】

x=float(input()) def f(x): return 3**x # 二次Lagrange多项式插值 def Lagrange_2(x0,x1,x2,x): l0 = ((x-x1)*(x-x2)) / ((x0-x1)*(x0-x2)) l1 = ((x-x0)*(x-x2)) / ((x1-x0)*(x1-x2)) l2 = ((x-x0)*(x-x1)) / ((x2-x0)*(x2-x1)) y = l0*f(x0)+l1*f(x1)+l2*f(x2) return y Y = Lagrange_2(0,1,2,x) print("%.5f" % Y)

【测试】

1.33 4.53780

 

1.3 n阶Lagrange插值公式

由一阶二阶可以推广到n阶,n阶Lagrange插值公式如下: 在这里插入图片描述 在这里插入图片描述

数学公式看着太抽象了,还是结合题目写成代码易懂些。

【例题】 在这里插入图片描述 【代码】

from math import e,exp print("请分别输入插值点x的值:") # 输入x的值 listX = [float(num) for num in input().strip().split(" ")] def f(x): return e**(x**2-1) # 获得对应的y值 def getlistY(listX): listY=[] for x in listX: y=f(x) listY.append(y) return listY # 获得l的值的函数,k为x的个数 def l(k,x,n): sum=1 for i in range(n+1): if i!=k: sum *= (x-listX[i])/(listX[k]-listX[i]) return sum # 求近似值的函数,n为Lagrange插值的阶数 def P(n,x): listY = getlistY(listX) sum = 0 for i in range(n+1): sum += l(i,x,n)*listY[i] return sum print("请输入待估测值X:") X=float(input()) # 分别输出不同阶的Lagrange插值近似值 for n in range(1,5): print("%d阶Lagrange插值近似值为: %.4f" %(n,P(n,X)))

【测试】

请分别输入插值点x的值: 1.0 1.1 1.2 1.3 1.4 请输入待估测值X: 1.25 1阶Lagrange插值近似值为: 1.5842 2阶Lagrange插值近似值为: 1.7442 3阶Lagrange插值近似值为: 1.7557 4阶Lagrange插值近似值为: 1.7550

 

2.Newton插值

在学习Newton插值公式之前,我们需要先引入差商的概念。

我们从一阶差商看起:设有函数f(x)以及一系列互不相等的自变量x0, x1,…, xn(即在i≠ j时,xi ≠xj)的值 f(xi) , 称f[xi , xj]为f (x)在点xi , xj处的一阶差商。其计算公式为:

在这里插入图片描述 类推可知二阶差商的计算公式为:

在这里插入图片描述 则n阶差商公式为:

在这里插入图片描述 由差商的定义可知,高阶差商是两个低一阶差商的差商。一般我们用差商表来表示各阶差商的值。

在这里插入图片描述

【例题】 在这里插入图片描述 【代码】

x0,x1,x2,x3=map(float,input().split()) y0,y1,y2,y3=map(float,input().split()) # 计算一阶差商的函数 def f(X1,X2,Y1,Y2): F = (Y1-Y2)/(X1-X2) return F # 一阶差商 F01 = f(x0,x1,y0,y1) F12 = f(x1,x2,y1,y2) F23 = f(x2,x3,y2,y3) # 二阶差商 F02 = (F01-F12)/(x0-x2) F13 = (F12-F23)/(x1-x3) # 三阶差商 F03 = (F02-F13)/(x0-x3) print("%d阶差商的值为:%.6f" %(1,F01)) print("%d阶差商的值为:%.6f" %(2,F02)) print("%d阶差商的值为:%.6f" %(3,F03))

【测试】

2 2.1 2.2 2.3 1.414214 1.449138 1.483240 1.516575 1阶差商的值为:0.349240 2阶差商的值为:-0.041100 3阶差商的值为:0.009167

当然,差商还可以通过更直观的均差表得出:(函数值为0阶均差)

在这里插入图片描述

经过一大坨复杂的数学证明,Newton插值多项式显然满足差商形式的插值条件。那么,我们可以由差商表得到Newton差商公式: 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 Newton插值公式相较于Lagrange插值公式有着巨大的优点,即其增加一个节点时,只需要再增加一项即可,没必要像Lagrange插值那样全部重新计算。

Newton插值公式的递推公式为:

在这里插入图片描述 【例题】

在这里插入图片描述 【代码】

print("请分别输入xk的值:") x0,x1,x2,x3,x4=map(float,input().split()) print("请分别输入f(xk)的值:") y0,y1,y2,y3,y4=map(float,input().split()) # 计算一阶差商的函数 def f(X1,X2,Y1,Y2): F = (Y1-Y2)/(X1-X2) return F # 一阶差商 F01 = f(x0,x1,y0,y1) F12 = f(x1,x2,y1,y2) F23 = f(x2,x3,y2,y3) F34 = f(x3,x4,y3,y4) # 二阶差商 F02 = (F01-F12)/(x0-x2) F13 = (F12-F23)/(x1-x3) F24 = (F23-F34)/(x2-x4) # 三阶差商 F03 = (F02-F13)/(x0-x3) F14 = (F13-F24)/(x1-x4) # 四阶差商 F04 = (F03-F14)/(x0-x4) # 计算四阶Newton插值的函数 def Newton(x): y = y0 + F01*(x-x0) + F02*(x-x0)*(x-x1) + F03*(x-x0)*(x-x1)*(x-x2) + F04*(x-x0)*(x-x1)*(x-x2)*(x-x3) return y print("请输入待估计的X的值:") X = float(input()) Y = Newton(X) print("利用四阶Newton插值公式计算出的f(X)结果为:%.3f" %Y)

【测试】

请分别输入xk的值: 0.40 0.55 0.65 0.80 0.90 请分别输入f(xk)的值: 0.41075 0.57815 0.69675 0.88811 1.02652 请输入待估计的X的值: 0.596 利用四阶Newton插值公式计算出的f(X)结果为:0.632

 

3.Hermite插值

在实际问题中,对于所构造的插值多项式,不仅要求函数值相等,而且要求其插值光滑,即要求节点处的导数值也相等。导数的阶数越高则光滑度越高。此类插值多项式称为Hermite插值多项式,也叫带导数的插值多项式。

Hermite插值满足的条件:

在这里插入图片描述

Hermite插值公式:

在这里插入图片描述 在实际情况中,我们最常使用的是两点三次Hermite插值,将n=1代入Hermite插值公式可得两点三次Hermite插值公式:

在这里插入图片描述 两点三次Hermite插值的基函数分别为:

在这里插入图片描述 为了便于理解,我们还是通过例题来体会Hermite插值算法。

【例题】

在这里插入图片描述 【代码】

print("请分别输入x的值:") x0,x1=map(float,input().split()) print("请分别输入y的值:") y0,y1=map(float,input().split()) print("请分别输入y'的值:") y00,y11=map(float,input().split()) def Hermite(x0,x1,y0,y1,y00,y11,x): L0 = (x-x1)/(x0-x1) L1 = (x-x0)/(x1-x0) F0 = ((1+2*L1)*y0 + (x-x0)*y00) F1 = ((1+2*L0)*y1 + (x-x1)*y11) H = F0*(L0**2) + F1*(L1**2) return H print("请输入待估测的X的值:") X = float(input()) H = Hermite(x0,x1,y0,y1,y00,y11,X) print("经两点三次Hermite插值得到的近似值为:%.5f" %H)

【测试】

请分别输入x的值: 1 2 请分别输入y的值: 0 0.693147 请分别输入y'的值: 1 0.5 请输入待估测的X的值: 1.5 经两点三次Hermite插值得到的近似值为:0.40907

 

4.分段插值与样条插值

对于代数插值来说,当插值多项式的次数很高时,逼近效果往往很不理想。其原因是,当n增大时,即节点加密时,f(x)与插值多项式的差别将会越来越大, 特别是在两端会发出激烈的振荡,这种现象叫龙格(Runge)现象。为了防止龙格现象的影响过大,我们要慎用高次插值,取而代之的是使用分段低次插值法。

所谓分段插值,就是将被插值函数分成几个小段,然后逐段多项式化。在各个子段上构造好插值多项式后,把它们装配到一起即可作为整个区间[a,b]上的插值函数。

在实际的工业生产中要求插值曲线既要尽可能简单,又要在曲线的连接处比较光滑。即这样的分段插值函数在分段上要求多项式次数低,还要求在节点上连续且存在连续的低阶导数,我们把满足这样条件的插值函数称为样条插值函数。样条插值函数所对应的曲线称为样条曲线,其节点称为样点,这种插值方法也被称为样条插值。

样条插值虽然理解起来比较复杂,但在做了某些近似简化后,样条的数学模型只是分段的三次多项式曲线。

尽管三次样条函数S(x)与分段Hermite插值函数具有很多共同点,但三次样条与分段Hermite插值有着本质区别:三次样条函数S(x)自身是光滑的,除了两个端点外其不需要知道 f 的导数值;而分段Hermite插值则完全依赖于f 在所有插值点的导数值。

在这里插入图片描述 三次样条插值一定满足以下条件:

在这里插入图片描述  

5.插值余项与误差估计

设R(x)为余项(截断误差),f(x)为函数准确值,P(x)为插值函数估计值,则误差R(x)的公式为:

在这里插入图片描述 由罗尔定理可以推出:

在这里插入图片描述 在这里插入图片描述 由此公式可以导出Lagrange插值、Newton插值、Hermite插值等插值公式的误差估计公式:

1.Lagrange插值的误差估计:

在这里插入图片描述

2.Newton插值的误差估计:

在这里插入图片描述 3.Hermite插值的误差估计:

在这里插入图片描述 易知两点三次Hermite插值的误差估计:

在这里插入图片描述 4.分段插值的误差估计:

在这里插入图片描述

 

6.曲线拟合

在科学实验和统计分析中,除了可以用插值逼近获得函数近似值,也可以使用曲线拟合的方法获得误差最小的近似函数。与误差较大的插值逼近不同,曲线拟合不需要经过所有数据节点,其适用于数据量较大且对误差要求较高的情况。

用几何来通俗地解释,曲线拟合便是用已知平面内的一组点确定一条曲线,使该曲线能在整体上刻画这组点的变化趋势而不需通过每个点,我们称这种方法为曲线拟合,所求出的曲线称为拟合曲线。

在这里插入图片描述 我们通常用“误差的平方和最小”这个准则来进行曲线拟合,这种方法也称为曲线拟合的最小二乘法。为了更好地表示曲线拟合的曲线拟合,我们需要引入线性代数中的向量内积。

设u,v为两个n维向量,则它们的内积(u,v)的表达式为: 在这里插入图片描述 内积有三个主要的性质:

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述   设φk(x)为基函数,ak为待求的系数,则待求的拟合函数P(x)的表达式为: 在这里插入图片描述 我们可以把这个式子写成正规方程组的形式:

在这里插入图片描述 在这里插入图片描述 我们通常将基函数φm(x)取值为x^m,其中m=0,1,2…

在这里插入图片描述 是不是感觉很抽象?

没错,我也不是很懂。

所以我们还是得通过具体题目的代码来理解这个拟合的过程。

【例题】

在这里插入图片描述 【代码】

import numpy as np # 基函数向量 a0 = np.array([[1],[1],[1],[1],[1]]) # Φ0 a1 = np.array([[0.4],[1.0],[2.0],[4.0],[10]]) # Φ1 r = np.array([[0.4053],[1.0071],[2.0167],[3.9963],[10.0165]]) # r b00 = b01 = b10 = b11 = r0 = r1 = 0 # 求矩阵元素值(内积) for i in range(0,5): b00 += a0[i]*a0[i] # (Φ0,Φ0) b01 += a0[i]*a1[i] # (Φ0,Φ1) b10 += a1[i]*a0[i] # (Φ1,Φ0) b11 += a1[i]*a1[i] # (Φ1,Φ1) r0 += a0[i]*r[i] # (Φ0,r) r1 += a1[i]*r[i] # (Φ1,r) # 解含有矩阵的方程,求出系数a,b的值 b = (r1*b00-r0*b10) / (b00*b11-b01*b10) a = (r0-b01*b) / b00 print("请输入X的值:") X = float(input()) Y = b*X+a print("f(x)经拟合的近似值为:%.2f" % Y)

【测试】

请输入X的值: 1.33 f(x)经拟合的近似值为:1.34

 

三.数值微积分 1.梯形公式与中矩形公式

梯形公式:(两点,n=1时具有一次代数精度)

在这里插入图片描述 在这里插入图片描述 梯形公式的余项:

在这里插入图片描述

中矩形公式:

在这里插入图片描述 在这里插入图片描述  

2.Simpson公式

Simpson公式(三点,n=2时具有三次代数精度):

在这里插入图片描述 在这里插入图片描述 Simpson公式的余项:

在这里插入图片描述

【例题】 在这里插入图片描述 【代码】

from math import e print("请输入a,b的值:") inp=input().split(' ') a=float(inp[0]) b=float(inp[1]) def f(x): y=(x**2)*(e**x) return y def Simpson(a,b): y = (1/6)*(b-a)*(f(a)+4*f((a+b)/2)+f(b)) return y Y = Simpson(a,b) print("结果为:%.5f" % Y)

【测试】

请输入a,b的值: 0 1 结果为:0.72783

 

3.Cotes公式

Cotes系数表:

在这里插入图片描述 Cotes公式的余项:

在这里插入图片描述

当n为奇数时,Cotes公式具有n次代数精度;当n为偶数时,Cotes公式具有n+1次代数精度。

为了更高的精度,通常我们选取n=4时的Cotes公式使用,其具有五次代数精度:

在这里插入图片描述

【例题】

在这里插入图片描述 【代码】

from math import sin print("请输入a,b的值:") inp=input().split(' ') a=float(inp[0]) b=float(inp[1]) def f(x): if(x==0): y=1 else: y=sin(x)/x return y # n=4时的Cotes公式 def Cotes(a,b): h = (b-a)/4 y = (b-a) * ((7/90)*f(a) + (16/45)*f(a+h) + (2/15)*f(a+2*h) + (16/45)*f(a+3*h) + (7/90)*f(b)) return y Y = Cotes(a,b) print("结果为:%.5f" % Y)

【测试】

请输入a,b的值: 0 1 结果为:0.94608

通过比较梯形公式、Simpson公式和Cotes公式的结果可以发现其精度依次上升。

【例题】

在这里插入图片描述 【代码】

from math import sin,e print("请输入a,b的值:") inp=input().split(' ') a=float(inp[0]) b=float(inp[1]) def f(x): y=x*sin(x)*(e**x) return y # 梯形公式 def Trapezoid(a,b): y = (1/2)*(b-a)*(f(a)+f(b)) return y # Simpson公式 def Simpson(a,b): y = (1/6)*(b-a)*(f(a)+4*f((a+b)/2)+f(b)) return y # Cotes公式 def Cotes(a,b): h = (b-a)/4 y = (b-a) * ((7/90)*f(a) + (16/45)*f(a+h) + (2/15)*f(a+2*h) + (16/45)*f(a+3*h) + (7/90)*f(b)) return y Y1 = Trapezoid(a,b) Y2 = Simpson(a,b) Y3 = Cotes(a,b) print("梯形公式的结果为:%.5f" %Y1) print("Simpson公式的结果为:%.5f" %Y2) print("Cotes公式的结果为:%.5f" %Y3)

【测试】

请输入a,b的值: 0 1 梯形公式的结果为:1.14368 Simpson公式的结果为:0.64471 Cotes公式的结果为:0.64365

(梯形公式这误差有那么亿点点大啊。。。。)  

4.复化求积公式

与插值类似,计算积分的时候也会出现龙格现象,故在次数过高时还是需要使用分段低阶的方法。  

4.1 复化梯形公式

将求积区间分成n个小区间,之后在每个小区间上分别用梯形公式求积,再将结果累加起来,就可以得到复化梯形公式。

复化梯形公式的余项为:

在这里插入图片描述

复化梯形公式的算法如下:

在这里插入图片描述 在这里插入图片描述 【例题】

在这里插入图片描述 【代码】

from math import log print("请分别输入a,b,n的值:") inp=input().split(' ') a = float(inp[0]) b = float(inp[1]) n = int(inp[2]) def f(x): return log(x) # 复化梯形公式 def Complex_Trapezoid(a,b,n): h = (b-a)/n # 步长 T = 0 for i in range(1,n): T += f(a+i*h) y = (h/2)*(f(a)+2*T+f(b)) return y Y = Complex_Trapezoid(a,b,n) print("结果为:%.5f" % Y)

【测试】

请分别输入a,b,n的值: 3.2 5 6 结果为:2.52426

 

4.2 复化Simpson公式

复化Simpson公式:

在这里插入图片描述 复化Simpson公式的余项为:

在这里插入图片描述

复化Simpson公式的算法如下:

在这里插入图片描述 在这里插入图片描述 【例题】

在这里插入图片描述 【代码】

from math import sin,sqrt print("请分别输入a,b,n的值:") inp=input().split(' ') a = float(inp[0]) b = float(inp[1]) n = int(inp[2]) def f(x): y = sqrt(4-(sin(x)**2)) return y # 复化Simpson公式 def Complex_Simpson(a,b,n): h = (b-a)/n # 步长 x = a+(h/2) S1 = f(x) S2 = 0 for i in range(1,n): S1 += f(a+i*h+h/2) S2 += f(a+i*h) S = (h/6)*(f(a)+4*S1+2*S2+f(b)) return S Y = Complex_Simpson(a,b,n) print("结果为:%.5f" % Y)

【测试】

请分别输入a,b,n的值: 0.5 1.1 7 结果为:1.11997

 

4.3 复化Cotes公式

【例题】 在这里插入图片描述 【代码】

print("请输入a,b的值:") inp = input().split(' ') a = float(inp[0]) b = float(inp[1]) n = 5 def f(x): return 1/(x**2+x**4) # 复化Cotes公式 def Complex_Cotes(a,b,n): h = (b-a)/n sum0 = sum1 = sum2 = sum3 = sum4 = 0 for i in range(1,n): sum0 += f(a+i*h) for i in range(0,n): sum1 += f(a+i*h+h/5) sum2 += f(a+i*h+2*h/5) sum3 += f(a+i*h+3*h/5) sum4 += f(a+i*h+4*h/5) return (h/288)*(19*f(a)+19*f(b)+38*sum0+75*sum1+50*sum2+50*sum3+75*sum4) Y = Complex_Cotes(a,b,n) print("结果为:%.4f" %Y)

【测试】

请输入a,b的值: 0.8 1 结果为:0.1393

 

5.变步长梯形公式

变步长的梯形求积算法的实现步骤:

在这里插入图片描述 在这里插入图片描述 【例题】 在这里插入图片描述 【代码】

import math print("请分别输入a,b的值:") inp = input().split(' ') a = float(inp[0]) b = float(inp[1]) e = 0.0001 # 误差 def f(x): if(x==0): return 1 else: return 1/(x**2+x**4) h = b-a T1 = (h/2)*(f(b)+f(a)) # 变步长梯形求积 while True: s = 0 x = a+h/2 while(x


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3