Calcul d'intégrales définies: algorithmes de base

image
Cette publication décrit les méthodes les plus simples pour calculer les intégrales des fonctions d'une variable sur un segment, également appelées formules de quadrature. En rÚgle générale, ces méthodes sont implémentées dans des bibliothÚques mathématiques standard telles que la bibliothÚque scientifique GNU pour C, SciPy pour Python et autres. La publication vise à démontrer comment ces méthodes fonctionnent "sous le capot" et à attirer l'attention sur certains problÚmes de précision et de performance des algorithmes. Je voudrais également noter la relation entre les formules en quadrature et les méthodes d'intégration numérique des équations différentielles ordinaires, à propos desquelles je veux écrire une autre publication.


Définition de l'intégrale


Intégrale (selon Riemann) d'une fonction f ( x ) sur le segment [ a ; b ] La limite suivante est appelée:


 i n t b a f ( x ) d x = l i m D e l t a x t o 0 s u m n - 1 i = 0 f ( x i i ) ( x i + 1 - x i ) , ( 1 )       


oĂč  Deltax= max lbracexi+1−xi rbrace - finesse de la partition, x0=a , xn=b ,  xii - un nombre arbitraire sur le segment [xi;xi+1] .


Si l'intĂ©grale de la fonction existe, alors la valeur limite est la mĂȘme quelle que soit la partition, si seulement elle Ă©tait suffisamment petite.
image
La définition géométrique est plus claire - l'intégrale est égale à l'aire du trapÚze courbe délimitée par l'axe 0 x , le graphique de la fonction et les lignes droites x = a et x = b (région remplie sur la figure).


Formules en quadrature


La dĂ©finition de l'intĂ©grale (1) peut ĂȘtre réécrite sous la forme


I= intbaf(x)dx approxIn=(b−a) sumn−1i=0wif( xii),  (2)


oĂč wi - coefficients de pondĂ©ration, dont la somme doit ĂȘtre Ă©gale Ă  1, et les coefficients eux-mĂȘmes - tendent Ă  zĂ©ro avec un nombre croissant n points auxquels la fonction est calculĂ©e.


L'expression (2) est la base de toutes les formules en quadrature (c'est-Ă -dire les formules pour le calcul approximatif de l'intĂ©grale). Le dĂ©fi est de sĂ©lectionner des points  lbrace xii rbrace et poids wi de sorte que la somme du cĂŽtĂ© droit se rapproche le plus prĂ©cisĂ©ment possible de l'intĂ©grale requise.


TĂąche de calcul


Ensemble de fonctions f(x) pour lequel il existe un algorithme de calcul des valeurs à tout moment de l'intervalle [a;b] (Je veux dire les points représentés par un nombre à virgule flottante - il n'y a pas de fonctions Dirichlet là-bas!).


Il est nĂ©cessaire de trouver la valeur approximative de l'intĂ©grale  intbaf(x)dx .
Les solutions seront implémentées dans Python 3.6.


Pour vĂ©rifier les mĂ©thodes, utilisez l'intĂ©grale  int3/20 left[2x+ frac1 sqrtx+1/16 right]dx=17/4 .


Approximation constante par morceaux


Les formules de quadrature idéalement simples résultent de l'application de l'expression (1) "au front":


In= sumn−1i=0f( xii)(xi+1−xi)


Parce que de la mĂ©thode de division d'un segment par des points  lbracexi rbrace et sĂ©lectionnez des points  lbrace xii rbrace la valeur limite ne dĂ©pend pas, alors nous les choisissons pour qu'elles puissent ĂȘtre facilement calculĂ©es - par exemple, nous prenons la partition uniformĂ©ment, et pour les points de calcul de la fonction nous considĂ©rons les options: 1)  xii=xi ; 2)  xii=xi+1 ; 3)  xii=(xi+xi+1)/2 .


Nous obtenons respectivement les méthodes des rectangles de gauche, des rectangles de droite et des rectangles avec un milieu.


Implémentation
def _rectangle_rule(func, a, b, nseg, frac): """  .""" dx = 1.0 * (b - a) / nseg sum = 0.0 xstart = a + frac * dx # 0 <= frac <= 1    , #    , #     dx for i in range(npoints): sum += func(xstart + i * dx) return sum * dx def left_rectangle_rule(func, a, b, nseg): """  """ return _rectangle_rule(func, a, b, nseg, 0.0) def right_rectangle_rule(func, a, b, nseg): """  """ return _rectangle_rule(func, a, b, npoints, 1.0) def midpoint_rectangle_rule(func, a, b, nseg): """    """ return _rectangle_rule(func, a, b, nseg, 0.5) 

Pour analyser les performances des formules en quadrature, nous construisons un graphique de l'erreur dans les coordonnées "le nombre de points est la différence entre le résultat numérique et l'exact".


image


Ce que vous pouvez remarquer:


  1. Une formule avec un point médian est beaucoup plus précise qu'avec un point droit ou gauche
  2. L'erreur de la formule avec le milieu tombe plus vite que les deux autres
  3. Avec une trĂšs petite partition, l'erreur de la formule avec le milieu commence Ă  augmenter
    Les deux premiers points sont liĂ©s au fait que la formule des rectangles avec un milieu a un deuxiĂšme ordre d'approximation, c'est-Ă -dire |In−I|=O(1/n2) , et les formules des rectangles droit et gauche sont du premier ordre, c'est-Ă -dire |In−I|=O(1/n) .
    Une augmentation de l'erreur lors du broyage de l'Ă©tape d'intĂ©gration est associĂ©e Ă  une augmentation de l'erreur d'arrondi lors de la sommation d'un grand nombre de termes. Cette erreur se dĂ©veloppe comme |In−I|=O(1/n) cela ne permet pas l'intĂ©gration pour atteindre la prĂ©cision de la machine.
    Conclusion: les mĂ©thodes des rectangles Ă  points droit et gauche ont une faible prĂ©cision, qui croĂźt aussi lentement avec le raffinement de la partition. Par consĂ©quent, ils n'ont de sens qu'Ă  des fins de dĂ©monstration. La mĂ©thode des rectangles avec un point mĂ©dian a un ordre d'approximation plus Ă©levĂ©, ce qui lui donne une chance d'ĂȘtre utilisĂ© dans des applications rĂ©elles (plus de dĂ©tails ci-dessous).

Approximation linéaire par morceaux


L'étape logique suivante consiste à approximer la fonction intégrable sur chacun des sous-segments par une fonction linéaire, qui donne la formule en quadrature des trapÚzes:


In= sumn−1i=0 fracf(xi)+f(xi+1)2(xi+1−xi)  (3)


image
Illustration de la méthode trapézoïdale pour n = 1 et n = 2.


Dans le cas d'une grille uniforme, les longueurs de tous les segments de la partition sont égales et la formule a la forme


In=h left( fracf(a)+f(b)2+ sumn−1i=1f(a+ih) right), h= fracban  (3a)


Implémentation
 def trapezoid_rule(func, a, b, nseg): """  nseg -  ,    [a;b]""" dx = 1.0 * (b - a) / nseg sum = 0.5 * (func(a) + func(b)) for i in range(1, nseg): sum += func(a + i * dx) return sum * dx 

AprÚs avoir tracé l'erreur en fonction du nombre de points de partage, nous voyons que la méthode trapézoïdale a également un second ordre d'approximation et donne généralement des résultats légÚrement différents de la méthode du rectangle médian (ci-aprÚs simplement la méthode du rectangle).
image


ContrÎle de précision de calcul


Définir le nombre de points de partage comme paramÚtre d'entrée n'est pas trÚs pratique, car il est généralement nécessaire de calculer l'intégrale non pas avec une densité de partition donnée, mais avec une erreur donnée. Si l'intégrande est connue à l'avance, alors nous pouvons estimer l'erreur à l'avance et choisir une étape d'intégration telle que la précision spécifiée est certainement atteinte. Mais c'est rarement le cas dans la pratique (et en général, n'est-il pas plus facile, avec la fonction connue à l'avance, d'intégrer l'intégrale à l'avance?), Par conséquent, une procédure d'ajustement automatique du pas à une erreur donnée est nécessaire.


Comment mettre cela en Ɠuvre? Une des mĂ©thodes simples pour estimer l'erreur - la rĂšgle de Runge - la diffĂ©rence dans les valeurs des intĂ©grales calculĂ©es Ă  partir de n et 2 n points, donne une estimation d'erreur:  Delta2n approx|I2n−In| . La mĂ©thode trapĂ©zoĂŻdale est plus pratique pour doubler la finesse d'une partition que la mĂ©thode des rectangles avec un point central. Lors du calcul par la mĂ©thode trapĂ©zoĂŻdale, pour doubler le nombre de points, de nouvelles valeurs de la fonction ne sont nĂ©cessaires qu'au milieu des segments de la partition prĂ©cĂ©dente, c'est-Ă -dire l'approximation prĂ©cĂ©dente de l'intĂ©grale peut ĂȘtre utilisĂ©e pour calculer la suivante.


À quoi sert la mĂ©thode du rectangle?

La mĂ©thode du rectangle ne nĂ©cessite pas de calculer les valeurs de la fonction aux extrĂ©mitĂ©s du segment. Cela signifie qu'il peut ĂȘtre utilisĂ© pour des fonctions qui ont des caractĂ©ristiques intĂ©grables aux bords du segment (par exemple, sin x / x ou x -1/2 de 0 Ă  1). Par consĂ©quent, la mĂ©thode d'extrapolation prĂ©sentĂ©e ci-dessous fonctionnera exactement de la mĂȘme maniĂšre pour la mĂ©thode du rectangle. La diffĂ©rence avec la mĂ©thode trapĂ©zoĂŻdale est seulement que lorsque l'Ă©tape est divisĂ©e par deux, le rĂ©sultat des calculs prĂ©cĂ©dents est ignorĂ©, cependant, vous pouvez tripler le nombre de points, puis la valeur prĂ©cĂ©dente de l'intĂ©grale peut Ă©galement ĂȘtre utilisĂ©e pour calculer un nouveau. Dans ce cas, les formules d'extrapolation doivent ĂȘtre adaptĂ©es Ă  un rapport diffĂ©rent d'Ă©tapes d'intĂ©gration.


De là, nous obtenons le code suivant pour la méthode trapézoïdale avec contrÎle de précision:


 def trapezoid_rule(func, a, b, rtol = 1e-8, nseg0 = 1): """  rtol -     nseg0 -    """ nseg = nseg0 old_ans = 0.0 dx = 1.0 * (b - a) / nseg ans = 0.5 * (func(a) + func(b)) for i in range(1, nseg): ans += func(a + i * dx) ans *= dx err_est = max(1, abs(ans)) while (err_est > abs(rtol * ans)): old_ans = ans ans = 0.5 * (ans + midpoint_rectangle_rule(func, a, b, nseg)) #      #       nseg *= 2 err_est = abs(ans - old_ans) return ans 

Avec cette approche, l'intégrande ne sera pas calculée plusieurs fois à un moment donné, et toutes les valeurs calculées sont utilisées pour le résultat final.


Mais est-il possible d'obtenir une prĂ©cision plus Ă©levĂ©e avec le mĂȘme nombre de calculs de fonction? Il s'avĂšre que c'est possible, il existe des formules qui fonctionnent plus prĂ©cisĂ©ment que la mĂ©thode trapĂ©zoĂŻdale sur la mĂȘme grille.


Approximation parabolique par morceaux


L'Ă©tape suivante consiste Ă  approximer la fonction avec des Ă©lĂ©ments paraboliques. Cela nĂ©cessite que le nombre de segments de la partition soit pair, puis les paraboles peuvent ĂȘtre tracĂ©es Ă  travers des triplets de points avec des abscisses {( x 0 = a , x 1 , x 2 ), ( x 2 , x 3 , x 4 ), ..., ( x n -2 , x n -1 , x n = b )}.



Illustration d'une approximation parabolique par morceaux Ă  3 et 5 points ( n = 2 et n = 3).


Approcher l'intégrale de la fonction sur chacun des segments [ x k ; x k +2 ] par l'intégrale de l'approximation parabolique sur ce segment et en supposant que les points sont uniformément répartis ( x k +1 = x k + h ), on obtient la formule de Simpson :


ISimps,n= sumn/2−1i=0 frach3[f(x2i)+4f(x2i+1)+f(x2i+2)]== frach3[f(a)+4f(a+h)+2f(a+2h)+...+4f(bh)+f(b)]  (4)


La formule (4) donne directement une implémentation «naïve» de la méthode Simpson:


En-tĂȘte de spoiler
 def simpson_rule(func, a, b, nseg): """  nseg -  ,    [a;b]""" if nseg%2 = 1: nseg += 1 dx = 1.0 * (b - a) / nseg sum = (func(a) + 4 * func(a + dx) + func(b)) for i in range(1, nseg / 2): sum += 2 * func(a + (2 * i) * dx) + 4 * func(a + (2 * i + 1) * dx) return sum * dx / 3 

Pour estimer l'erreur, vous pouvez utiliser le mĂȘme calcul de l'intĂ©grale avec les Ă©tapes h et h / 2 - mais voici le problĂšme, lors du calcul de l'intĂ©grale avec un pas plus petit, le rĂ©sultat du calcul prĂ©cĂ©dent devra ĂȘtre ignorĂ©, bien que la moitiĂ© des nouveaux calculs de fonction soient aux mĂȘmes points qu'auparavant.


Heureusement, vous pouvez Ă©viter de perdre du temps machine si vous implĂ©mentez la mĂ©thode Simpson de maniĂšre plus ingĂ©nieuse. AprĂšs avoir regardĂ© de plus prĂšs, nous notons que l'intĂ©grale par la formule de Simpson peut ĂȘtre reprĂ©sentĂ©e par deux intĂ©grales par la formule trapĂ©zoĂŻdale avec des Ă©tapes diffĂ©rentes. Cela se voit le plus clairement dans le cas de base de l'approximation de l'intĂ©grale sur trois points (a,f0), (a+h,f1), (a+2h,f2) :


ISimps,2= frach3(f0+4f1+f2)= frac43h left( fracf0+f12+ fracf1+f22 droite)− frac13 cdot2h fracf0+f22== frac4Itrap,2−Itrap,13


Ainsi, si nous mettons en Ɠuvre la procĂ©dure de rĂ©duction du pas de moitiĂ© et stockons les deux derniers calculs par la mĂ©thode trapĂ©zoĂŻdale, la mĂ©thode Simpson avec contrĂŽle de prĂ©cision est mise en Ɠuvre plus efficacement.


Quelque chose comme ça ...
 class Quadrature: """    """ __sum = 0.0 __nseg = 1 #    __ncalls = 0 #      def __restart(func, x0, x1, nseg0, reset_calls = True): """    .       """ if reset_calls: Quadrature.__ncalls = 0 Quadrature.__nseg = nseg0 #           nseg0 Quadrature.__sum = 0.5 * (func(x0) + func(x1)) dx = 1.0 * (x1 - x0) / nseg0 for i in range(1, nseg0): Quadrature.__sum += func(x0 + i * dx) Quadrature.__ncalls += 1 + nseg0 return Quadrature.__sum * dx def __double_nseg(func, x0, x1): """  .       """ nseg = Quadrature.__nseg dx = (x1 - x0) / nseg x = x0 + 0.5 * dx i = 0 AddedSum = 0.0 for i in range(nseg): AddedSum += func(x + i * dx) Quadrature.__sum += AddedSum Quadrature.__nseg *= 2 Quadrature.__ncalls += nseg return Quadrature.__sum * 0.5 * dx def trapezoid(func, x0, x1, rtol = 1e-10, nseg0 = 1): """     . rtol -  , nseg0 -    """ ans = Quadrature.__restart(func, x0, x1, nseg0) old_ans = 0.0 err_est = max(1, abs(ans)) while (err_est > abs(rtol * ans)): old_ans = ans ans = Quadrature.__double_nseg(func, x0, x1) err_est = abs(old_ans - ans) print("Total function calls: " + str(Quadrature.__ncalls)) return ans def simpson(func, x0, x1, rtol = 1.0e-10, nseg0 = 1): """     . rtol -  , nseg0 -    """ old_trapez_sum = Quadrature.__restart(func, x0, x1, nseg0) new_trapez_sum = Quadrature.__double_nseg(func, x0, x1) ans = (4 * new_trapez_sum - old_trapez_sum) / 3 old_ans = 0.0 err_est = max(1, abs(ans)) while (err_est > abs(rtol * ans)): old_ans = ans old_trapez_sum = new_trapez_sum new_trapez_sum = Quadrature.__double_nseg(func, x0, x1) ans = (4 * new_trapez_sum - old_trapez_sum) / 3 err_est = abs(old_ans - ans) print("Total function calls: " + str(Quadrature.__ncalls)) return ans 

Comparez l'efficacité de la méthode trapézoïdale et parabole:


 >>> import math >>> Quadrature.trapezoid(lambda x: 2 * x + 1 / math.sqrt(x + 1 / 16), 0, 1.5, rtol=1e-9) Total function calls: 65537 4.250000001385811 >>> Quadrature.simpson(lambda x: 2 * x + 1 / math.sqrt(x + 1 / 16), 0, 1.5, rtol=1e-9) Total function calls: 2049 4.2500000000490985 

Comme vous pouvez le voir, avec les deux mĂ©thodes, la rĂ©ponse peut ĂȘtre obtenue avec une prĂ©cision assez Ă©levĂ©e, mais le nombre d'appels Ă  l'intĂ©grande est trĂšs diffĂ©rent - une mĂ©thode d'ordre supĂ©rieur est 32 fois plus efficace!


En traçant l'erreur d'intĂ©gration en fonction du nombre d'Ă©tapes, nous pouvons vĂ©rifier que l'ordre d'approximation de la formule de Simpson est quatre, c'est-Ă -dire erreur d'intĂ©gration numĂ©rique |ISimps,n−I|=O(1/n4) (et les intĂ©grales des polynĂŽmes cubiques utilisant cette formule sont calculĂ©es jusqu'aux erreurs d'arrondi pour tout n > 0!).
image
Par conséquent, une telle augmentation de l'efficacité se produit en comparaison avec la formule trapézoïdale simple.


Et ensuite?


La logique supplémentaire d'augmenter la précision des formules en quadrature est généralement compréhensible - si nous continuons à approximer la fonction avec des polynÎmes d'un degré toujours plus élevé, alors l'intégrale de ces polynÎmes rapprochera de plus en plus précisément l'intégrale de la fonction d'origine. Cette approche est appelée la construction de formules de Newton-Cotes quadratiques . Des formules contenant jusqu'à 8 ordres d'approximation sont connues, mais les termes alternatifs apparaissent parmi les coefficients de pondération w i dans (2), et les formules perdent de leur stabilité dans les calculs.


Essayons dans l'autre sens. L'erreur de la formule en quadrature est représentée par une série de puissances de l'étape d'intégration h . Une propriété remarquable de la méthode trapézoïdale (et des rectangles avec un point médian!) Est que pour elle cette série n'est constituée que de degrés pairs:


Itrap,n[f,a,b]= intbaf(x)dx+C2h2+C4h4+C6h6+..., h= fracban   (5)


L'extrapolation de Richardson est basée sur la recherche d'approximations successives de cette expansion: au lieu d'approximer l'intégrande par un polynÎme, à partir des approximations calculées de l'intégrale I(h) une approximation polynomiale est construite, qui pour h = 0 devrait donner la meilleure approximation à la vraie valeur de l'intégrale.


L'élargissement de l'erreur d'intégration dans les puissances paires de l'étape de partition accélÚre fortement la convergence de l'extrapolation, car pour l'approximation d'ordre 2 n , seules les valeurs n de l'intégrale sont nécessaires par la méthode trapézoïdale.


Si nous supposons que chaque terme suivant est infĂ©rieur au prĂ©cĂ©dent, alors nous pouvons exclure sĂ©quentiellement les degrĂ©s de h , ayant des approximations intĂ©grales calculĂ©es avec diffĂ©rentes Ă©tapes. Étant donnĂ© que l'implĂ©mentation ci-dessus nous permet facilement de diviser la partition en deux, il est pratique de considĂ©rer les formules des Ă©tapes h et h / 2.


Itrap,n−I approxC2h2; Itrap,2n−I approxC2 left( frach2 right)2


Il est facile de montrer que l'exception du terme supérieur de l'erreur de la formule trapézoïdale donnera exactement la formule de Simpson:


I=Itrap,2n−C2 left( frach2 right)2+O(h4) approxItrap,2n− fracItrap,2n−IpiĂšge,n1−22=ISimps,2n


En répétant une procédure similaire pour la formule Simpson, nous obtenons:


ISimps,2n−I approxC4 left( frach2 right)4; ISimps,n−I approxC4h4


I=ISimps,2n−C4 left( frach2 right)4+O(h6) approxISimps,2n− fracISimps,2n−ISimps,n1−24


Si vous continuez, le tableau suivant se profile:


2 ordre4 ordre6 ordre...
I 0,0
I 1,0I 1,1
I 2.0I 2.1I 2.2
.........

La premiÚre colonne contient les intégrales calculées par la méthode trapézoïdale. Lorsque vous vous déplacez de la ligne supérieure vers le bas, la division du segment devient deux fois plus petite et lorsque vous vous déplacez de la colonne de gauche vers la droite, l'ordre d'approximation de l'intégrale augmente (c'est-à-dire que la deuxiÚme colonne contient les intégrales par la méthode Simpson, etc.)


Les éléments du tableau, comme on peut le déduire de l'expansion (5), sont liés par la relation de récurrence:


Ii,j=Ii,j−1− fracIi,j−1−Ii−1,j−11− left( frachijhi droite)2=Ii,j−1− fracIi,j−1−Ii−1,j−11−22j   (6)


L'erreur d'approximation de l'intĂ©grale peut ĂȘtre estimĂ©e Ă  partir de la diffĂ©rence de formules de diffĂ©rents ordres sur une seule ligne, c'est-Ă -dire


 Deltai,j environIi,j−Ii,j−1


L'utilisation de l'extrapolation de Richardson avec l'intégration trapézoïdale est appelée la méthode de Romberg . Si la méthode Simpson prend en compte les deux valeurs précédentes par la méthode trapézoïdale, la méthode Romberg utilise toutes les valeurs précédemment calculées par la méthode trapézoïdale pour obtenir une estimation plus précise de l'intégrale.


Implémentation

Une méthode supplémentaire est ajoutée à la classe Quadrature


 class Quadrature: """    """ __sum = 0.0 __nseg = 1 #    __ncalls = 0 #      def __restart(func, x0, x1, nseg0, reset_calls = True): """    .       """ if reset_calls: Quadrature.__ncalls = 0 Quadrature.__nseg = nseg0 #          nseg0  Quadrature.__sum = 0.5 * (func(x0) + func(x1)) dx = 1.0 * (x1 - x0) / nseg0 for i in range(1, nseg0): Quadrature.__sum += func(x0 + i * dx) Quadrature.__ncalls += 1 + nseg0 return Quadrature.__sum * dx def __double_nseg(func, x0, x1): """  .       """ nseg = Quadrature.__nseg dx = (x1 - x0) / nseg x = x0 + 0.5 * dx i = 0 AddedSum = 0.0 for i in range(nseg): AddedSum += func(x + i * dx) Quadrature.__sum += AddedSum Quadrature.__nseg *= 2 Quadrature.__ncalls += nseg return Quadrature.__sum * 0.5 * dx def romberg(func, x0, x1, rtol = 1e-10, nseg0 = 1, maxcol = 5, reset_calls = True): """   nseg0 -     maxcol -   """ #   Itable = [[Quadrature.__restart(func, x0, x1, nseg0, reset_calls)]] i = 0 maxcol = max(0, maxcol) ans = Itable[i][i] error_est = max(1, abs(ans)) while (error_est > abs(rtol * ans)): old_ans = ans i += 1 d = 4.0 ans_col = min(i, maxcol) Itable.append([Quadrature.__double_nseg(func, x0, x1)] * (ans_col + 1)) for j in range(0, ans_col): diff = Itable[i][j] - Itable[i - 1][j] Itable[i][j + 1] = Itable[i][j] + diff / (d - 1.0) d *= 4.0 ans = Itable[i][ans_col] if (maxcol <= 1): #       error_est = abs(ans - Itable[i - 1][-1]) elif (i > maxcol): error_est = abs(ans - Itable[i][min(i - maxcol - 1, maxcol - 1)]) else: error_est = abs(ans - Itable[i - 1][i - 1]) print("Total function calls: " + str(Quadrature.__ncalls)) return ans 

Vérifions le fonctionnement de l'approximation d'ordre élevé:


 >>> Quadrature.romberg(lambda x: 2 * x + 1 / math.sqrt(x + 1/16), 0, 1.5, rtol=1e-9, maxcol = 0) #  Total function calls: 65537 4.250000001385811 >>> Quadrature.romberg(lambda x: 2 * x + 1 / math.sqrt(x + 1/16), 0, 1.5, rtol=1e-9, maxcol = 1) #  Total function calls: 2049 4.2500000000490985 >>> Quadrature.romberg(lambda x: 2 * x + 1 / math.sqrt(x + 1/16), 0, 1.5, rtol=1e-9, maxcol = 4) Total function calls: 257 4.250000001644076 

Nous sommes convaincus que, par rapport à la méthode parabole, le nombre d'appels à l'intégrande a encore diminué de 8 fois. Avec une augmentation supplémentaire de la précision requise, les avantages de la méthode Romberg deviennent encore plus prononcés:
image


Quelques notes


Remarque 1. Le nombre d'appels de fonction dans ces problĂšmes caractĂ©rise le nombre de sommes lors du calcul de l'intĂ©grale. La rĂ©duction du nombre de calculs de l'intĂ©grande permet non seulement d'Ă©conomiser des ressources informatiques (bien que ce soit Ă©galement le cas avec une implĂ©mentation plus optimisĂ©e), mais rĂ©duit Ă©galement l'effet des erreurs d'arrondi sur le rĂ©sultat. Ainsi, lorsque vous essayez de calculer l'intĂ©grale de la fonction de test, la mĂ©thode trapĂ©zoĂŻdale se bloque lorsque vous essayez d'obtenir une prĂ©cision relative de 5 × 10 -15 , la mĂ©thode parabole - avec la prĂ©cision souhaitĂ©e de 2 × 10 -16 (qui est la limite des nombres Ă  double prĂ©cision), et la mĂ©thode Romberg fait face au calcul test intĂ©gral jusqu'Ă  la prĂ©cision de la machine (avec une faible erreur de bit). Autrement dit, non seulement la prĂ©cision d'intĂ©gration est augmentĂ©e pour un nombre donnĂ© d'appels de fonction, mais Ă©galement la prĂ©cision maximale rĂ©alisable du calcul de l'intĂ©grale.


Remarque 2. Si la mĂ©thode converge lorsqu'une certaine prĂ©cision est spĂ©cifiĂ©e, cela ne signifie pas que la valeur calculĂ©e de l'intĂ©grale a la mĂȘme prĂ©cision. Tout d'abord, cela s'applique aux cas oĂč l'erreur spĂ©cifiĂ©e est proche de la prĂ©cision de la machine.


Remarque 3. Bien que la méthode de Romberg pour un certain nombre de fonctions fonctionne de maniÚre presque magique, elle suppose que l'intégrande a borné des dérivées d'ordre élevé. Cela signifie que pour les fonctions avec des plis ou des ruptures, cela peut s'avérer pire que les méthodes simples. Par exemple, intégrez f ( x ) = | x |:


 >>> Quadrature.trapezoid(abs, -1, 3, rtol=1e-5) Total function calls: 9 5.0 >>> Quadrature.simpson(abs, -1, 3, rtol=1e-5) Total function calls: 17 5.0 >>> Quadrature.romberg(abs, -1, 3, rtol=1e-5, maxcol = 2) Total function calls: 17 5.0 >>> Quadrature.romberg(abs, -1, 3, rtol=1e-5, maxcol = 3) Total function calls: 33 5.0 >>> Quadrature.romberg(abs, -1, 3, rtol=1e-5, maxcol = 4) Total function calls: 33 5.000001383269357 

Remarque 4. Il peut sembler que plus l'ordre d'approximation est Ă©levĂ©, mieux c'est. En fait, il vaut mieux limiter le nombre de colonnes dans le tableau de Romberg Ă  4-6. Pour comprendre cela, regardez la formule (6). Le deuxiĂšme terme est la diffĂ©rence de deux Ă©lĂ©ments consĂ©cutifs de la j -1Ăšme colonne divisĂ©e par environ 4 j . Parce que la jiĂšme colonne contient des approximations d'une intĂ©grale d'ordre 2 j , alors la diffĂ©rence elle-mĂȘme est de l'ordre de (1 / n i ) 2 j ~ 4 - ij . En tenant compte de la division, on obtient ~ 4 - ( i +1) j ~ 4 - j 2 . C'est-Ă -dire pour j ~ 7, le deuxiĂšme terme de (6) perd sa prĂ©cision aprĂšs la rĂ©duction des ordres lors de l'ajout de nombres Ă  virgule flottante, et une augmentation de l'ordre d'approximation peut conduire Ă  l'accumulation d'erreurs d'arrondi.


Remarque 5. Les parties intĂ©ressĂ©es peuvent utiliser les mĂ©thodes dĂ©crites pour trouver l'intĂ©grale dans l'intĂ©rĂȘt.  int10 sqrtx sinxdx et Ă©quivalent Ă  lui  int102t2 sint2dt . Comme on dit, ressentez la diffĂ©rence.


Conclusion


La description et la mise en Ɠuvre des mĂ©thodes de base de l'intĂ©gration numĂ©rique des fonctions sur une grille uniforme sont prĂ©sentĂ©es. Il est dĂ©montrĂ© comment, Ă  l'aide d'une simple modification, obtenir la classe de formules de quadrature en utilisant la mĂ©thode de Romberg sur la base de la mĂ©thode trapĂ©zoĂŻdale, ce qui accĂ©lĂšre considĂ©rablement la convergence de l'intĂ©gration numĂ©rique. La mĂ©thode fonctionne bien pour intĂ©grer des fonctions "ordinaires", c'est-Ă -dire variant faiblement sur l'intervalle d'intĂ©gration, n'ayant pas de singularitĂ©s aux bords du segment (voir remarque 5), oscillations rapides, etc.


( [3] — C++).


Littérature


  1. .. , .. . . .: . 1989.
  2. J. Stoer, R. Bulirsch. Introduction to Numerical Analysis: Second Edition. Springer-Verlag New York. 1993.
  3. WH Press, SA Teukolsky, WT Vetterling, BP Flannery. Numerical Recipes: Third Edition. Cambridge University Press. 2007.

Source: https://habr.com/ru/post/fr420867/


All Articles