วิธีการของรอมเบิร์ก
ในการวิเคราะห์เชิงตัวเลขวิธีของ Romberg [ 1 ]ใช้ในการประมาณค่าอินทิกรัลจำกัด โดยการใช้การขยายแบบ Richardson [ 2 ]ซ้ำๆ ตามกฎสี่เหลี่ยมคางหมูหรือกฎสี่เหลี่ยมผืนผ้า (กฎจุดกึ่งกลาง) การประมาณค่าจะสร้างอาร์เรย์สามเหลี่ยมวิธีของ Romberg เป็นสูตร Newton–Cotesซึ่งประเมินค่าอินทิกรัลที่จุดที่มีระยะห่างเท่ากัน อินทิกรัลต้องมีอนุพันธ์ต่อเนื่อง แม้ว่าจะได้ผลลัพธ์ที่ดีพอสมควรหากมีอนุพันธ์เพียงไม่กี่ตัว หากสามารถประเมินค่าอินทิกรัลที่จุดที่มีระยะห่างไม่เท่ากันได้ วิธีอื่นๆ เช่นGaussian quadratureและClenshaw–Curtis quadratureโดยทั่วไปจะมีความแม่นยำมากกว่า
วิธีการนี้ตั้งชื่อตามเวอร์เนอร์ รอมเบิร์กผู้ซึ่งตีพิมพ์วิธีการนี้ในปี 1955
วิธี
โดยใช้วิธีนี้สามารถกำหนดแบบอุปนัยได้โดย ที่และในสัญกรณ์บิ๊กโอข้อผิดพลาดสำหรับR ( n , m )คือ: [ 3 ]
การประมาณค่าแบบที่ศูนย์R ( n , 0)เทียบเท่ากับกฎสี่เหลี่ยมคางหมูที่มี2n + 1จุด การประมาณค่าแบบที่หนึ่งR ( n , 1)เทียบเท่ากับกฎของซิมป์สันที่มี2n + 1 จุด การประมาณค่าแบบที่สองR ( n , 2)เทียบเท่ากับกฎของบูลที่มี2n + 1 จุด การประมาณ ค่า แบบที่ไกลออกไปจะแตกต่างจากสูตรของนิวตัน-โคทส์ โดยเฉพาะอย่างยิ่ง การประมาณค่าแบบรอมเบิร์กที่ไกลออกไปจะขยายกฎของบูลในลักษณะ ที่เล็กน้อยมาก โดยปรับเปลี่ยนน้ำหนักให้เป็นอัตราส่วนที่คล้ายกับในกฎของบูล ในทางตรงกันข้าม วิธีการของนิวตัน-โคทส์ที่ไกลออกไปจะสร้างน้ำหนักที่แตกต่างกันมากขึ้นเรื่อยๆ จนในที่สุดนำไปสู่น้ำหนักบวกและลบขนาดใหญ่ นี่แสดงให้เห็นว่าวิธีการของนิวตัน-โคทส์แบบพหุนามที่มีการประมาณค่าในระดับสูงนั้นไม่สามารถลู่เข้าได้สำหรับอินทิกรัลจำนวนมาก ในขณะที่การอินทิเกรตแบบรอมเบิร์กมีความเสถียรมากกว่า
โดยการติดป้ายกำกับค่าประมาณของเราเป็นแทนที่จะเป็นเราสามารถทำการประมาณค่าแบบริชาร์ดสันโดยใช้สูตรความคลาดเคลื่อนที่กำหนดไว้ด้านล่าง: เมื่อเราได้ค่าประมาณ แล้ว เราสามารถติดป้ายกำกับค่าประมาณเหล่านั้นเป็นได้
เมื่อการประเมินค่าฟังก์ชันมีค่าใช้จ่ายสูง อาจเป็นการดีกว่าที่จะแทนที่การประมาณค่าแบบพหุนามของริชาร์ดสันด้วยการประมาณค่าแบบตรรกยะที่เสนอโดยบูลีร์ชและสโตเออร์ (1967 )
ตัวอย่างทางเรขาคณิต
ในการประมาณพื้นที่ใต้เส้นโค้ง จะใช้กฎสี่เหลี่ยมคางหมูโดยเริ่มจากชิ้นส่วนเดียว จากนั้นสองชิ้น สี่ชิ้น และต่อไปเรื่อยๆ




หลังจากได้ค่าประมาณตามกฎสี่เหลี่ยมคางหมูแล้วจึงใช้การ ประมาณค่าแบบริชาร์ดสัน
- สำหรับการคำนวณรอบแรก จะใช้ค่าประมาณแบบสองชิ้นและหนึ่งชิ้นในสูตร4 × (แม่นยำกว่า) − (แม่นยำน้อยกว่า)/3จาก นั้นจึงใช้สูตรเดียวกันนี้ในการเปรียบเทียบประมาณการแบบสี่ชิ้นและแบบสองชิ้น และเช่นเดียวกันสำหรับประมาณการที่สูงกว่า
- สำหรับการวนซ้ำครั้งที่สอง จะใช้ค่าจากการวนซ้ำครั้งแรกในสูตร16 × (แม่นยำกว่า) − (แม่นยำน้อยกว่า)/15
- การทำซ้ำครั้งที่สามใช้เลขยกกำลังถัดไปของ 4: 64 × (แม่นยำกว่า) − (แม่นยำน้อยกว่า)/63โดยพิจารณาจากค่าที่ได้จากการวนซ้ำครั้งที่สอง
- กระบวนการนี้จะดำเนินต่อไปจนกว่าจะได้ค่าประมาณค่าเดียว
| จำนวนชิ้น | การประมาณค่ารูปสี่เหลี่ยมคางหมู | รอบแรก | รอบที่สอง | การทำซ้ำครั้งที่สาม |
|---|---|---|---|---|
| 4 MA − LA/3 | 16 MA − LA/15 | 64 MA − LA/63 | ||
| 1 | 0 | 4×16 − 0/3= 21.333... | 16×34.667 − 21.333/15= 35.556... | 64×42.489 − 35.556/63= 42.599... |
| 2 | 16 | 4×30 − 16/3= 34.666... | 16×42 − 34.667/15= 42.489... | |
| 4 | 30 | 4×39 − 30/3= 42 | ||
| 8 | 39 |
ตัวอย่าง
ตัวอย่างเช่นฟังก์ชันเกาส์เซียนจะถูกอินทิเกรตจาก 0 ถึง 1 นั่นคือฟังก์ชันข้อผิดพลาด erf(1) ≈ 0.842 700 792 949 715อาร์เรย์สามเหลี่ยมจะถูกคำนวณทีละแถว และการคำนวณจะสิ้นสุดลงหากค่าสองค่าสุดท้ายในแถวสุดท้ายแตกต่างกันน้อยกว่า10 −8
0.77174333 0.82526296 0.84310283 0.83836778 0.84273605 0.84271160 0.84161922 0.84270304 0.84270083 0.84270066 0.84243051 0.84270093 0.84270079 0.84270079 0.84270079
ผลลัพธ์ในมุมล่างขวาของตารางสามเหลี่ยมมีความถูกต้องตรงกับตัวเลขที่แสดง เป็นที่น่าทึ่งว่าผลลัพธ์นี้ได้มาจากการประมาณค่าที่ไม่แม่นยำนักซึ่งได้จากกฎสี่เหลี่ยมคางหมูในคอลัมน์แรกของตารางสามเหลี่ยม
การดำเนินการ
ต่อไปนี้เป็นตัวอย่างการนำวิธีการของ Romberg มาใช้ในคอมพิวเตอร์ (โดยใช้ภาษาโปรแกรม C ):
#include <stdio.h>#include <math.h>void print_row ( size_t i , double * R ) {printf ( "R[%2zu] = " , i );สำหรับ( size_t j = 0 ; j <= i ; ++ j ) {printf ( "%f " , R [ j ]);}printf ( " \n " );}/*ป้อนข้อมูล:(*f) : ตัวชี้ไปยังฟังก์ชันที่จะทำการอินทิเกรตa : ขีดจำกัดล่างข : ขีดจำกัดบนmax_steps: จำนวนขั้นตอนสูงสุดของกระบวนการacc : ความแม่นยำที่ต้องการผลลัพธ์:Rp[max_steps-1]: ค่าโดยประมาณของอินทิกรัลของฟังก์ชัน f สำหรับ x ในช่วง [a,b] ด้วยความแม่นยำ 'acc' และขั้นตอน 'max_steps'*/double romberg ( double ( * f )( double ), double a , double b , size_t max_steps , double acc ){double R1 [ max_steps ], R2 [ max_steps ]; // บัฟเฟอร์double * Rp = & R1 [ 0 ], * Rc = & R2 [ 0 ]; // Rp คือแถวก่อนหน้า, Rc คือแถวปัจจุบันdouble h = b - a ; //ขนาดขั้นตอนRp [ 0 ] = ( f ( a ) + f ( b )) * h * 0.5 ; // ขั้นตอนสี่เหลี่ยมคางหมูขั้นแรกพิมพ์แถว( 0 , Rp );สำหรับ( size_t i = 1 ; i < max_steps ; ++ i ) {h /= 2. ;double c = 0 ;size_t ep = 1 << ( i -1 ); //2^(n-1)สำหรับ( size_t j = 1 ; j <= ep ; ++ j ) {c += f ( a + ( 2 * j -1 ) * h );}Rc [ 0 ] = h * c + .5 * Rp [ 0 ]; // R(i,0)สำหรับ( size_t j = 1 ; j <= i ; ++ j ) {double n_k = pow ( 4 , j );Rc [ j ] = ( n_k * Rc [ j -1 ] - Rp [ j -1 ]) / ( n_k -1 ); // คำนวณ R(i,j)}// พิมพ์แถวที่ i ของ R, R[i,i] คือค่าประมาณที่ดีที่สุดจนถึงตอนนี้print_row ( i , Rc );ถ้า( i > 1 และfabs ( Rp [ i -1 ] - Rc [ i ]) < acc ) {ส่งคืนRc [ i ];}// สลับ Rn และ Rc เนื่องจากเราต้องการเฉพาะแถวสุดท้ายเท่านั้นdouble * rt = Rp ;Rp = Rc ;Rc = rt ;}return Rp [ max_steps -1 ]; // ส่งคืนค่าประมาณที่ดีที่สุดของเรา}ต่อไปนี้คือตัวอย่างการใช้งานวิธี Romberg (ในภาษาโปรแกรม Python ):
จากnumpy นำเข้าarangedef romberg ( f , a , b , maxorder ):""" ประมาณค่าอินทิกรัลโดยใช้การอินทิเกรตแบบรอมเบิร์ก อาร์กิวเมนต์: f: ฟังก์ชันที่จะทำการอินทิเกรต a: ขีดจำกัดล่างของการอินทิเกรต ข: ขีดจำกัดบนของการอินทิเกรต maxorder: ความลึกสูงสุดของการเรียกซ้ำ การส่งคืนสินค้า: ค่าโดยประมาณของอินทิกรัล """ตรวจสอบว่าa < b และisinstance ( maxorder , int )minstepsize = float ( ( 1. / 2 ) ** maxorder * ( b - a ) )# อัลกอริทึมได้รับการทำให้ง่ายขึ้นและเร็วขึ้นด้วยการแคชf = จดจำ( f )@จดจำกฎdef ( h , ลำดับ):ถ้า( ลำดับ== 1 ):ผลรวมย่อย= ( f ( a ) + f ( b )) / 2partial_sum += sum ( map ( f , arange ( a + h , b - h / 2 , h )))คืนค่าh * ผลรวมย่อย# สูตรการประมาณค่าแบบริชาร์ดสันW = 4. ** ( ลำดับ- 1 )คืนค่า( W * rule ( h , order - 1 ) - rule ( 2 * h , order - 1 )) / ( W - 1 )ส่งคืนกฎ( ขนาดขั้นตอนขั้นต่ำ, ลำดับสูงสุด)def memorize ( f ):_cache_ = dict ()def cachedf ( * argv ):ถ้าไม่ใช่( argv ใน_cache_ ):_cache_ [ argv ] = f ( * argv )คืนค่า_cache_ [ argv ]cachedf._cache_ = _cache_ส่งคืนแคชdef main ():จากnumpy นำเข้าsin , exp , pi# ตัวอย่าง: อินทิเกรต sin(x)*exp(x/6)+x บนช่วง [0,2pi]a , b , f = 0 , 2 * pi , lambda x : sin ( x ) * exp ( x / 6 ) + xexact = 36 * ( 1 - exp ( pi / 3 )) / 37 + 2 * pi ** 2print ( "Order Value Rel_Err \n " + '-' * 30 )สำหรับลำดับสูงสุดในช่วง( 1 , 9 ):ค่า= romberg ( f , a , b , maxorder )err = abs ( value - exact ) / exactพิมพ์( ' %2d ' % maxorder , ' %.15f ' % value , ' %1.1e ' % err )หลัก()ลิงก์ภายนอก
- ROMBINT – โค้ดสำหรับMATLAB (ผู้เขียน: Martin Kacenak)
- เครื่องมือคำนวณปริพันธ์ออนไลน์ฟรีที่ใช้ Romberg, Fox–Romberg, Gauss–Legendre และวิธีการเชิงตัวเลขอื่นๆ
- การนำวิธีของ Romberg มาใช้ใน SciPy
- Romberg.jl — การใช้งานใน ภาษา Julia (รองรับการแยกตัวประกอบแบบใดก็ได้ไม่ใช่แค่จุด)