插值计算椭圆周长并与计算误差

题目

I ( b ) = ∫ 0 π / 2 1 + ( b 2 − 1 ) cos ⁡ 2 t d t I(b)= \int _{0}^{\pi /2}\sqrt{1+(b^{2}-1)\cos ^{2}t}dt I(b)=0π/21+(b21)cos2t dt
上述函数的导数为
I ′ ( b ) = ∫ 0 π / 2 b cos ⁡ 2 t 1 + ( b 2 − 1 ) cos ⁡ 2 t d t I^{\prime}(b)= \int _{0}^{\pi /2}\frac{b \cos ^{2}t}{\sqrt{1+(b^{2}-1)\cos ^{2}t}}dt I(b)=0π/21+(b21)cos2t bcos2tdt
采用三种方法中最好的方法计算这一积分

(1)利用数值积分的方法给出 I ( b ) I ( b ) I(b) b = 0 , 0.1 , 0.2 , … , 1 b = 0 , 0.1 , 0.2 , \dots , 1 b=0,0.1,0.2,,1 (可以直接计算精确值的,用精确值),用Newton插值方法得到5个椭圆的周长(五个椭圆具体见上一篇图片文件的初步处理与椭圆的最小二乘拟合)。
(2)利用数值积分的方法给出 I ′ ( b ) I^{\prime} ( b ) I(b), 在 b = 0 , 0.1 , 0.2 , … , 1 b = 0 , 0.1 , 0.2 , \dots , 1 b=0,0.1,0.2,,1 (可以直接计算精确值的,用精确值),用Hermite插值方法得到5个椭圆的周长。

算法介绍

Netown插值

根据均差的定义,把 x x x看成 [ a , b ] [a,b] [a,b]上的一点,可以得到
f ( x ) = f ( x 0 ) + f [ x , x 0 ] ( x − x 0 ) f(x)=f(x_{0})+f \left[ x,x_{0}\right](x-x_{0}) f(x)=f(x0)+f[x,x0](xx0)

f ( x , x 0 ) = f ( x 0 , x 1 ) + f [ x , x 0 , x 1 ] ( x − x 1 ) f ( x , x _ { 0 } ) = f ( x _ { 0 } , x _ { 1 } ) + f [ x , x _ { 0 } , x _ { 1 } ] ( x - x _ { 1 } ) f(x,x0)=f(x0,x1)+f[x,x0,x1](xx1)

将后一个式子带入前一个式子,得到
f ( x ) = f ( x 0 ) + f ( x 0 ) + f ( x − x 0 ) + f [ x 0 , x 0 , x 1 ] ( x − x 0 ) ( x − x 0 ) f ( x ) = f ( x _ { 0 } ) + f ( x _ { 0 } ) + f ( x - x _ { 0 } ) + f [ x _ { 0 } , x _ { 0 } , x _ { 1 } ] ( x - x _ { 0 } ) ( x - x _ { 0 } ) f(x)=f(x0)+f(x0)+f(xx0)+f[x0,x0,x1](xx0)(xx0)

再由 f [ x 1 , x 0 , x 1 ] = f [ x 0 , x 1 , x 2 ] + f [ x , x 0 , x 1 , x 2 ] ( x − x 2 ) f \left[ x_{1},x_{0},x_{1}\right] =f \left[ x_{0},x_{1},x_{2}\right] +f \left[ x,x_{0},x_{1},x_{2}\right](x-x_{2}) f[x1,x0,x1]=f[x0,x1,x2]+f[x,x0,x1,x2](xx2)

得到
f ( x ) = f ( x 0 ) + f ( x 0 ) + f ( x 0 − x 1 ) + f [ x 0 − x 1 ) ( x − x 0 ) ( x − x 0 ) ( x − x 1 ) f ( x ) = f ( x _ { 0 } ) + f ( x _ { 0 } ) + f ( x _ { 0 } - x _ { 1 } ) + f [ x _ { 0 } - x _ { 1 } ) ( x - x _ { 0 } ) ( x - x _ { 0 } ) ( x - x _ { 1 } ) f(x)=f(x0)+f(x0)+f(x0x1)+f[x0x1)(xx0)(xx0)(xx1)

+ f [ x , x 0 , x 1 , x 2 ] ( x − x 0 ) ( x − x 0 ) ( x − x 1 ) +f [x, x _ { 0 } , x _ { 1 },x_2 ] ( x - x _ { 0 } ) ( x - x _ { 0 } ) ( x - x _ { 1 } ) +f[x,x0,x1,x2](xx0)(xx0)(xx1)

Hermite插值

设在结点 a ≤ x 0 < x 1 < ⋯ < x n ≤ b a \leq x _ { 0 }< x _ { 1 } < \cdots < x _ { n } \leq b ax0<x1<<xnb f ( x j ) = y j , m j = f ′ ( x j ) f(x_j)=y_j,m_j=f^\prime(x_j) f(xj)=yj,mj=f(xj), ( j = 0 , 1 , ⋯   , n ) (j=0,1,\cdots,n) (j=0,1,,n),求多项式 H ( X ) H(X) H(X),满足条件
H ( x j ) = y j , H ′ ( x j ) = m j ( j = 0 , 1 , ⋯   , n ) H(x_{j})=y_{j},H^{\prime}(x_{j})=m_{j}(j=0,1, \cdots ,n) H(xj)=yj,H(xj)=mj(j=0,1,,n)

一共给出了 2 n + 2 2n+2 2n+2个已知条件,可以唯一确定一个次数不超过 2 n + 1 2n+1 2n+1的多项式
H 2 n + 1 ( x ) = a 0 + a 1 x + ⋯ + a 2 n + 1 x 2 n + 1 H_{2n+1}(x)=a_{0}+a_{1}x+ \cdots +a_{2n+1}x^{2n+1} H2n+1(x)=a0+a1x++a2n+1x2n+1

低阶分段插值

为了避免插值高阶冗余现象导致逼近效果差的现象,我们可以采用分段低次插值得到不同区间内的分段函数。

代码模块

环境:python=3.9.0 sympy=1.12 numpy=1.23.5

导入模块

import sympy as sp
import numpy as np
import time

Newton插值

def Newton_Interger(data_x,formula,t):

    start=time.time()
    # 计算对应点的函数值
    n=len(data_x)
    y=[0]*n
    for i in range(n):
        y[i]=formula.evalf(subs={t:data_x[i]})
    # 创建差商表
    Z=[[0] *n for _ in range(n)]

    for i in range(n):
        Z[i][0]=y[i]
    # 计算差商值
    for i in range(n):
        for j in range(1,i+1):
            Z[i][j]=(Z[i][j-1]-Z[i-1][j-1])/(data_x[i]-data_x[i-j])
    # 计算插值多项式
    res=0 
    for  i in range(n):
        C=Z[i][i]
        for j in range(i):
            C*=(t-data_x[j])
        res+=C
    end=time.time()
    print("time:",end-start)
    
    return res.expand()

Netown法计算椭圆周长

def Compute_N(a,b):

    # 构建函数
    T=sp.Symbol('t')
    formula=(a**2*sp.cos(T)**2+b**2*sp.sin(T)**2)**(1/2)
    data_t=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,\
    1.2,1.3,1.4,1.5]
    formula0=Newton_Interger(formula=formula,data_x=\
        [data_t[0],data_t[-1]],t=T)
    R0=4*Romberg(formula0,T,0,sp.pi/2,1e-6)
    print(R0.evalf())
    print(formula0)
    formula1=Newton_Interger(formula=formula,data_x=\
        [data_t[0],data_t[7],data_t[-1]],t=T)
    R1=4*Romberg(formula1,T,0,sp.pi/2,1e-6)
    print(R1.evalf())
    print(formula1)
    formula2=Newton_Interger(formula=formula,data_x=\
        [data_t[0],data_t[5],data_t[10],data_t[-1]],t=T)
    R2=4*Romberg(formula2,T,0,sp.pi/2,1e-6)
    print(R2.evalf())
    print(formula2)
    formula3=Newton_Interger(formula=formula,data_x=\
        [data_t[0],data_t[4],data_t[8],data_t[12],data_t[-1]],t=T)
    R3=4*Romberg(formula3,T,0,sp.pi/2,1e-6)
    print(R3.evalf())
    print(formula3)
    formula4=Newton_Interger(formula=formula,data_x=\
        [data_t[0],data_t[3],data_t[6],data_t[9],data_t[12],\
            data_t[-1]],t=T)
    R4=4*Romberg(formula4,T,0,sp.pi/2,1e-6)
    print(R4.evalf())
    print(formula4)

计算结果

def Compute(a,b):

    print("Compute_N:")
    Compute_N(a,b)
    #print("Compute_H:")
    #Compute_H(a,b)
    #print("Separte:")
    #Separte(a,b)  

Compute(a=42.8755430086675,b=40.8633914591405)

Compute(a=41.8822717617791,b=39.0938947820857)

Compute(a=40.8633914591405,b=36.5409190520717)

Compute(a=40.3106783148759,b=34.9340215298776)

Compute(a=37.2328566002455,b=30.8883836902119)

误差衡量

对于下述的椭圆形式:
x 2 a 2 + y 2 b 2 = 1 ( a > 0 , b > 0 ) . \frac { x ^ { 2 } } { a ^ { 2 } } + \frac { y ^ { 2 } } { b ^ { 2 } } = 1 ( a > 0 , b > 0 ) . a2x2+b2y2=1(a>0,b>0).

可以通过拉马努金椭圆计算公式快速计算出结果
C ≈ π ( a + b ) ( 1 + 3 λ 2 10 + 4 − 3 λ 2 ) , λ = a − b a + b . C \approx \pi ( a + b ) \left( 1 + \frac { 3 \lambda ^ { 2 } } { 1 0 + \sqrt { 4 - 3 \lambda ^ { 2 } } } \right) , \lambda = \frac { a - b } { a + b } . Cπ(a+b)(1+10+43λ2 3λ2),λ=a+bab.

详细代码

这里只是以Newton为例,详细代码见github代码

参考资料

[1].图片文件的初步处理与椭圆的最小二乘拟合

[2].拉马努金椭圆计算公式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值