自适应高斯勒让德法则(Adaptive Gauss-Legendre)(python,数值积分)

第四十二篇 自适应高斯勒让德法则

之前的文章中,就已经提出了调整小区间的长度来改变积分函数的值。因为,如果函数在某些区域变化的很快,可能需要一个更窄的区间,而如果函数是缓慢变化,更改成一个长区间代替几个小区间,但精度是完全一样的。手动执行这些修改显然会很繁琐,所以在这这篇中,将介绍一种自适应算法来自动调整区间的长度。
这种自适应方法的基础是通过比较两个具有不同精度的法则获得的结果而得到每个区间上的误差估计。假设更精确的法则给出“准确”的结果,因此误差为两个法则的差值。如果这个误差估计超过了指定的容许范围,则将考虑将区间分成两个,并重复这个过程。
该算法从整个范围的的单个区间开始,迭代将其分成更小的区间,直到所有区间都满足误差容许值。
一个典型的例子在下图。第一张图涉及到整个范围的积分。字母F(表示“false”)表示超过了容差,因此该范围被分成两个宽度相等的区间。图(b)显示了第二次迭代,涉及到对两个区间的积分。字母T(表示“true”)表示右条带满足误差准则;但是F表示左边的条带没有,所以这个范围又被分成两个更小的等宽区间。图6©显示了第三次迭代,涉及对范围左半部分的两个区间进行积分。得到右半边已经满足了容差但左边一半没有,需要进一步细分区间,.如图(d)所示,,所有带现在标记T,因此所有区间都满足容差。在每条上使用更精确的法则,然后总结和输出。一旦区间满足误差公差并标记为T,就不会再次验证。
在这里插入图片描述
该算法显示了绝对误差和相对误差标准的必要性。从工程角度看,相对误差是最重要的,因为它将误差限制在某些指定的比例。然而,绝对误差也需要作为一种保障,在任何区间的面积变得非常接近于零时,相对误差容错性可能不合理。在这种情况下绝对错误将优先考虑。

程序如下

#重复g高斯勒让德法则
import numpy as np
import math
import B
nr1=1
answer1=np.zeros((nr1));err1=np.zeros((nr1));limits1=np.zeros((nr1,2))
answer2=np.zeros((nr1));err2=np.zeros((nr1));limits2=np.zeros((nr1,2))
conv1=np.array([False])
conv2=np.array([False])
#法则2比法则1更准确,nsp2>nsp1
limits1[0,:]=(0.0,1.0);abserr=1e-3;relerr=1e-3;nsp1=1;nsp2=4
samp1=np.zeros((nsp1,1));samp2=np.zeros((nsp2,1));wt1=np.zeros((nsp1));wt2=np.zeros((nsp2))
B.gauss_legendre(samp1,wt1);B.gauss_legendre(samp2,wt2)
print('自适应高斯法则')
print('绝对值错误容差',abserr)
print('相对错误容差',relerr)
print('积分上下限',limits1)
print('低阶高斯勒让德法则',nsp1)
print('高阶高斯勒让德法则',nsp2)
def f63(x):
    f63=x**(1.0/7.0)/(x**2.0+1.0)
    return f63
while(True):
    area=0;tot_err=0;ct=0;cf=0
    for i in range(1,nr1+1):
        if (not conv1[i-1])==True:
            a=limits1[i-1,0];b=limits1[i-1,1]
            nsp1=samp1.shape[0];nsp2=samp2.shape[0]
            wr=b-a;hr=0.5*wr;area1=0;area2=0
            for j in range(1,nsp1+1):
                area1=area1+wt1[j-1]*hr*f63(a+hr*(1.0-samp1[j-1,0]))
            for j in range(1,nsp2+1):
                area2=area2+wt2[j-1]*hr*f63(a+hr*(1.0-samp2[j-1,0]))
            errest=area1-area2;tol=max(abserr,relerr*abs(area2))
            ans=area2;verdict=False
            if abs(errest)<tol:
                verdict=True
            answer1[i-1]=ans;conv1[i-1]=verdict;err1[i-1]=errest
        if bool(conv1[i-1])==True:
            ct=ct+1
        else:
            cf=cf+1
        area=area+answer1[i-1];tot_err=tot_err+err1[i-1]
    if cf==0:
        print('重复数量',nr1)
        print('         小分区上下限         区域面积       误差')
        for i in range(1,nr1+1):
            for j in range(1,3):
                print('{:12.4}'.format(limits1[i-1,j-1]),end='')
            print('{:16.8}'.format(answer1[i-1]),end='')
            print('{:16.8}'.format(err1[i-1]))
        print('解和总误差',area,tot_err)
        break
    limits2[:]=limits1[:];answer2[:]=answer1[:];conv2[:]=conv1[:];err2[:]=err1[:]
    nr2=nr1;nr1=ct+2*cf
    answer1=np.zeros((nr1));conv1=np.zeros((nr1));err1=np.zeros((nr1));limits1=np.zeros((nr1,2))
    conv1[:]=False;inew=0
    for i in range(1,nr2+1):
        if conv2[i-1]==True:
            inew=inew+1
            limits1[inew-1,:]=limits2[i-1,:];answer1[inew-1]=answer2[i-1]
            err1[inew-1]=err2[i-1];conv1[inew-1]=True
        else:
            inew=inew+1;limits1[inew-1,0]=limits2[i-1,0]
            limits1[inew-1,1]=(limits2[i-1,0]+limits2[i-1,1])*0.5
            inew=inew+1
            limits1[inew-1,0]=(limits2[i-1,0]+limits2[i-1,1])*0.5
            limits1[inew-1,1]=limits2[i-1,1]
    answer2=np.zeros((nr1));conv2=np.zeros((nr1));err2=np.zeros((nr1));limits2=np.zeros((nr1,2))
            

终端输出结果
在这里插入图片描述

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深渊潜航

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值