def FiniteDifferenceNewton(f,fp,p0,tolerance):
= p0 - f(p0)/fp(p0)
p = abs(p-p0)
abs_error = p
p0
while abs_error > tolerance:
= p0 - f(p0)/fp(p0)
p = abs(p-p0)
abs_error = p
p0 return p
(Pertemuan 2) Metode Root-Finding: Secant, Regula-Falsi, Finite-Difference
Secant Method, Regula-Falsi Method, Finite-Difference
Kembali ke Metode Numerik
Materi Pembahasan:
Finite-Difference Newton Method
Secant Method
Regula-False Method
Sequence Barisan
Aitken Method
Steffensen Method
Diskusi
Praktikum Metode Numerik PTA 2024-2025
Departemen Matematika FMIPA Universitas Indonesia
Metode Newton dengan Beda Hingga (Finite-Difference Newton’s Method)
Salah satu kekurangan Metode Newton yang biasa adalah harus mengetahui rumus turunannya secara analitik. Sebelum adanya CAS seperti SymPy, turunan analitik harus dihitung secara manual dengan kalkulus. Kalau bentuk rumus untuk \(f(x)\) sangat rumit, perhitungan turunan menjadi jauh lebih rumit. Untuk menghindari menghitung turunan secara analitik, kita dapat menggunakan definisi turunan (yang menggunakan limit):
\[f'(x) = \lim_{h \rightarrow 0} \frac{f(x+h) - f(x)}{h}\]
dengan memilih nilai \(h\) yang cukup kecil (sayangnya, kita tidak bisa membuat limit \(h\) menuju nol). Nilai \(h\) yang cukup kecil itu disebut suatu beda hingga (finite difference).
Sehingga, modifikasi metode Newton ini bisa disebut Metode Newton dengan Beda Hingga (Finite-Difference Newton’s Method). Untuk fungsi \(f\) yang kontinu, akar persamaan \(f(x) = 0\) bisa ditentukan dengan iterasi sebagai berikut:
\[\begin{align*} p_n &= p_{n-1} - \frac{f(p_{n-1})}{\left(\frac{f\left(p_{n-1}+h\right)-f(p_{n-1})}{h}\right)} \\ &= p_{n-1} - \frac{f(p_{n-1})h}{f(p_{n-1}+h)-f(p_{n-1})} \end{align*}\]
dengan tebakan awal \(p_0\). Perhatikan bahwa \(f'(p_{n-1})\) pada metode Newton yang biasa itu telah digantikan dengan
\[f'(p_{n-1}) \approx \frac{f(p_{n-1}+h) - f(p_{n-1})}{h}\]
Tujuan modifikasi tersebut adalah agar iterasi dapat dilakukan pada titik di mana turunannya tidak ada, atau ketika turunan analitik sulit diperoleh.
from numpy import sin, cos, tan, log, exp, sqrt
= input("Masukkan fungsi: ")
formula def f(x):
return eval(formula)
def fp(x, h=10**(-12)):
return (f(x+h)-f(x))/h
= eval(input("Masukkan titik awal iterasi: "))
starting_point = eval(input("Masukkan toleransi aproksimasi: "))
tolerance
= FiniteDifferenceNewton(f,fp,starting_point,tolerance)
akar_fd
print(f"Akar dari persamaan f(x) = {formula} adalah x = {akar_fd}")
Masukkan fungsi: 2*x - 3*cos(x) + exp(-5*x) - 9
Masukkan titik awal iterasi: -1
Masukkan toleransi aproksimasi: 10**(-7)
Akar dari persamaan f(x) = 2*x - 3*cos(x) + exp(-5*x) - 9 adalah x = -0.5073224866379543
Metode Secant
Pada Metode Newton dengan Beda Hingga, nilai \(h\) konstan. Kalau kita punya dua tebakan awal yang saling dekat, misal \(p_0\) dan \(p_1\), kita bisa saja memanfaatkannya dengan memasang \(h = p_1 - p_0\). Bahkan, ketika iterasi \(p_n\) sudah semakin dekat menuju akar, jarak antara \(p_{n-1}\) dan \(p_{n-2}\) menjadi semakin kecil. Sehingga, dengan memasang nilai \(h = p_{n-2} - p_{n-1}\) atau \(h = p_{n-1} - p_{n-2}\), kita berhasil membuat limit \(h\) menuju nol.
Modifikasi ini disebut Metode Secant, dengan iterasi sebagai berikut untuk menentukan penyelesaian \(f(x) = 0\) dengan fungsi \(f\) yang kontinu:
\[\begin{align*} p_n &= p_{n-1} - \frac{f(p_{n-1})}{\left(\frac{f(p_{n-1})-f(p_{n-2})}{p_{n-1}-p_{n-2}}\right)} \\ &= p_{n-1} - \frac{f(p_{n-1})(p_{n-1} - p_{n-2})}{f(p_{n-1}) - f(p_{n-2})} \end{align*}\]
Dibandingkan Metode Newton yang biasa, Metode Secant menggantikan \(f'(p_{n-1})\) dengan
\[f'(p_{n-1}) \approx \frac{f(p_{n-1}) - f(p_{n-2})}{p_{n-1} - p_{n-2}}\]
sehingga, tidak seperti Metode Newton yang hanya memerlukan satu tebakan awal, Metode Secant membutuhkan dua tebakan awal, yaitu \(p_0\) dan \(p_1\). Namun, dibandingkan dengan Metode Newton dengan Beda Hingga, nilai \(h\) atau beda hingga tersebut tidak perlu ditentukan secara manual.
Menariknya, Metode Secant memiliki order of convergence = \(\phi \approx 1.618\).
def Secant(f,p0,p1,tolerance):
= p1 - (f(p1)*(p1-p0))/(f(p1)-f(p0))
p = abs(p-p1)
abs_error = p1
p0 = p
p1
while abs_error > tolerance:
= p1 - (f(p1)*(p1-p0))/(f(p1)-f(p0))
p = abs(p-p1)
abs_error = p1
p0 = p
p1 return p
from numpy import sin, cos, tan, log, exp, sqrt
= input("Masukkan formula fungsi: ")
formula
def f(x):
return eval(formula)
= eval(input("Masukkan titik awal pertama: "))
titik_1 = eval(input("Masukkan titik awal kedua: "))
titik_2 = eval(input("Masukkan toleransi aproksimasi: "))
tolerance
= Secant(f,titik_1,titik_2,tolerance)
akar_secant
print(f"Akar dari persamaan f(x) = {formula} adalah x = {akar_secant}")
Masukkan formula fungsi: 2*x - 3*cos(x) + exp(-5*x) - 9
Masukkan titik awal pertama: -1
Masukkan titik awal kedua: -2
Masukkan toleransi aproksimasi: 10**(-7)
Akar dari persamaan f(x) = 2*x - 3*cos(x) + exp(-5*x) - 9 adalah x = -0.5073224866425831
Metode Regula Falsi
Sejauh ini, kita sudah membahas beberapa metode root-finding atau aproksimasi akar, yaitu:
- Metode Bisection
- Metode Fixed-Point
- Metode Newton biasa (dengan turunan analitik)
- Metode Newton dengan Beda Hingga (finite-difference Newton’s method)
- Metode Secant
Di antara semua metode tersebut, hanya Metode Bisection yang dijamin konvergen menuju akar di interval yang diberikan; semua metode lain ada kemungkinan divergen (menjauh dari akar, seperti metode fixed-point) atau gagal karena terjadi pembagian nol. Sayangnya, Metode Bisection termasuk metode yang pelan di antara metode numerik lainnya.
Untuk menjaga jaminan kekonvergenan oleh Metode Bisection tetapi memperbaiki kecepatan kekonvergenannya, kita bisa memodifikasi Metode Bisection, yaitu memodifikasi cara menentukan \(p\) yang baru yang akan mempersempit interval. Perhatikan bahwa Metode Bisection membutuhkan dua “tebakan awal” (lebih tepatnya dua batasan interval), sedangkan metode di atas yang juga membutuhkan dua tebakan awal hanyalah Metode Secant.
Apakah kita bisa menggunakan Metode Bisection, tetapi dengan modifikasi menentukan \(p\) seperti Metode Secant, agar mendapatkan order of convergence seperti Metode Secant?
Jawabannya adalah bisa, dan modifikasi tersebut dinamakan Metode Regula Falsi. Sehingga, Metode Regula Falsi bisa disebut perpaduan antara Metode Bisection dan Metode Secant.
Sebenarnya, perbedaan algoritma Metode Bisection dan Metode Regula Falsi hanya di satu baris saja, yaitu mengubah baris
\[p=\frac{a+b}{2}\]
menjadi
\[p = b - \frac{f(b)(b-a)}{f(b) - f(a)}\]
sesuai Metode Secant. Perhatikan bahwa Metode Secant biasanya membutuhkan dua tebakan awal yang tidak harus sama dengan batasan interval, sedangkan Metode Regula Falsi secara otomatis menggunakan kedua batasan interval \([a,b]\) sebagai dua tebakan awal.
Untuk pembuatan kode Metode Regula Falsi, kami serahkan ke kalian. Gampang, kok! Tinggal mengubah beberapa baris saja (baris yang menentukan nilai \(p\) yang baru) pada kode Metode Bisection, yaitu mengambil baris tersebut dari kode Metode Secant, kemudian menyesuaikan kedua tebakan awal menjadi kedua batasan interval.
Seperti Metode Secant, Metode Regula Falsi juga memiliki order of convergence = \(\phi \approx 1.618\).
def RegulaFalsi(f, p0, p1, tol, n = 1000):
= 2
i = f(p0)
q0 = f(p1)
q1
while i < n:
= p1 - q1*(p1 - p0)/(q1 - q0)
p
if abs(p - p1) < tol:
return p
+= 1
i
= f(p)
q
if q * q1 < 0 :
= p1
p0 = q1
q0
= p
p1 = q
q1
return "Aproksimasi Gagal"
from numpy import sin, cos, tan, log, exp, sqrt, pi
= input("Masukkan formula fungsi: ")
formula
def f(x):
return eval(formula)
= eval(input("Masukkan titik awal pertama: "))
titik_1 = eval(input("Masukkan titik awal kedua: "))
titik_2 = eval(input("Masukkan toleransi aproksimasi: "))
tolerance
= RegulaFalsi(f, titik_1, titik_2, tolerance)
akar_falsi
print(f"Akar dari persamaan f(x) = {formula} adalah x = {akar_falsi}")
Apa itu barisan? (penjelasan tanpa kode)
Suatu “barisan” (sequence) adalah sekumpulan angka yang berurut. Artinya, pada suatu barisan, ada yang bisa disebut angka pertama (atau suku pertama), angka kedua (suku kedua), angka ketiga (suku ketiga), dan sebagainya. Banyaknya suku bisa berhingga maupun tak terhingga.
Suku-suku pada suatu barisan itu bisa saja ditentukan secara manual atau sesuka hati, atau bisa juga menggunakan rumus. Intinya, suku-suku suatu barisan itu bisa diperoleh dari manapun, bahkan dari hasil iterasi metode numerik (\(p_0\), \(p_1\), \(p_2\), \(p_3\), …) juga bisa.
Oleh karena itu, contoh barisan berhingga adalah hasil iterasi fixed-point, misalnya dengan \(g(x) = 1 + \frac{1}{x}\), tebakan awal \(p_0 = 2\), dan batas toleransi \(10^{-7}\):
\[\begin{align*} (& 1.5, 1.6666666666666665, 1.6, \\ & 1.625, 1.6153846153846154, \\ & 1.619047619047619, \dots, \\ & 1.6180339631667064) \end{align*}\]
Proses tersebut berakhir setelah 17 iterasi, sehingga barisan tersebut memiliki 17 suku.
Barisan tersebut bisa diberi nama, seperti \(p_n\) dengan \(n = 1, 2, 3, \dots, 17\), yang bisa dituliskan \(\left\{p_n\right\}_{n=1}^{17}\) dengan kurung kurawal.
Contoh barisan tak berhingga adalah barisan aritmetika dan barisan geometri, seperti:
\[(-5, -2, 1, 4, 7, 10, 13, 16, 19, \dots)\]
\[\left(16, 8, 4, 2, 1, \frac{1}{2}, \frac{1}{4}, \frac{1}{8}, \dots\right)\]
Barisan tak berhingga dengan nama \(p_n\) yang mulai dari suku \(n=1\) bisa ditulis \(\left\{p_n\right\}_{n=1}^{\infty}\) dengan kurung kurawal, atau singkatnya \((p_n)\) saja dengan kurung biasa (dengan begitu, biasanya ada asumsi bahwa barisan tersebut tak berhingga).
Metode Aitken
Alexander Aitken menemukan bahwa, untuk sembarang barisan (termasuk sembarang metode numerik) yang memiliki kekonvergenan linier, untuk nilai \(n\) yang besar, berlaku
\[\frac{p_{n+1} - p}{p_n - p} \approx \frac{p_{n+2} - p}{p_{n+1} - p}\]
di mana \(p\) adalah nilai yang ingin dicari, sedangkan \(p_n\), \(p_{n+1}\), dan \(p_{n+2}\) adalah tiga suku barisan (atau tiga hasil aproksimasi) berturut-turut. Artinya, perbandingan error (error ratio) antar dua pasang hasil iterasi (diperoleh dari tiga hasil iterasi berturut-turut) menjadi kurang lebih sama. Dengan manipulasi aljabar, diperoleh
\[p \approx p_n - \frac{\left(p_{n+1} - p_n\right)^2}{p_{n+2} - 2p_{n+1} + p_n}\]
seolah-olah ada jalur pintas untuk langsung mendapatkan nilai yang ingin dicari.
Tentu saja, sebelum menggunakan rumus ini, kita perlu menemukan tiga hasil aproksimasi pertama, yaitu \(p_0\), \(p_1\), dan \(p_2\). Kemudian, barulah kita tentukan \(p_3\) menggunakan rumus Aitken (hasil rumus Aitken biasa disebut \(\hat{p}_n\), sehingga bisa ditulis \(p_3 = \hat{p}_0\), karena perhitungan \(p_3\) memanfaatkan \(p_0\), \(p_1\) dan \(p_2\)).
Variabel \(\hat{p}\) biasa disebut p-hat atau p-cap (kata “hat” atau “cap” artinya topi).
Apabila kita definisikan \(\Delta p_n = p_{n+1} - p_n\) dan \(\Delta^2 p_n = p_{n+2} - 2p_{n+1} + p_n\), rumus Aitken bisa ditulis
\[\hat{p}_n = p_n - \frac{(\Delta p_n)^2}{\Delta^2 p_n}\]
sehingga teknik ini biasa disebut Aitken’s delta-squared (\(\Delta^2\)) method.
Catatan: dalam pembahasan metode Aitken/Steffensen, penulisan \(\Delta^2\) BUKAN berarti \((\Delta)^2\). Itu hanya penulisan saja.
Secara umum, apabila kita punya suku-suku suatu barisan yang berturut-turut yaitu \(p_1, p_2, p_3, \dots, p_{k-3}, p_{k-2}, p_{k-1}, p_{k}\), maka rumus Aitken bisa digunakan untuk menentukan \(\hat{p}_1, \hat{p}_2, \hat{p}_3, \dots, \hat{p}_{k-3}, \hat{p}_{k-2}\), yang semuanya merupakan aproksimasi nilai yang lebih akurat untuk hasil konvergen dari barisan tersebut (dengan asumsi kekonvergenan linier).
Perhatikan: - Kita hanya bisa berhenti sampai \(\hat{p}_{k-2}\), karena perhitungannya membutuhkan \(p_{k-2}\), \(p_{k-1}\) dan \(p_k\). - Harus ada minimal 3 suku yang diketahui, artinya \(k \ge 3\).
def Aitken(p):
= len(p)
k if k < 3:
return "Maaf, dibutuhkan minimal 3 suku yang diketahui."
# kalau lanjut ke sini, artinya k >= 3
= []
list_phat for i in range(k-2):
= p[i+1] - p[i]
Delta = p[i+2] - 2 * p[i+1] + p[i]
DeltaSquared = p[i] - (Delta)**2 / DeltaSquared
phat
list_phat.append(phat)return list_phat
try:
# input suatu list
= eval(input("Masukkan list suku-suku yang diketahui: "))
p except:
print("Maaf, terjadi error. Harap masukkan list dengan benar.")
else: # kalau tidak terjadi error
print("Berikut hasil metode Aitken:")
print(Aitken(p))
Masukkan list suku-suku yang diketahui: [2, 1.5, 1.6666666666666665, 1.6, 1.625]
Berikut hasil metode Aitken:
[1.625, 1.619047619047619, 1.6181818181818182]
Metode Steffensen: Penerapan Metode Aitken pada Metode Fixed Point
Aitken hanya menemukan rumus. Johan Frederik Steffensen menemukan bahwa, karena Metode Fixed-Point memiliki kekonvergen linier, metode Aitken bisa digunakan untuk mempercepat Metode Fixed-Point.
Secara umum, apabila kita berselang-seling antara menggunakan suatu metode dan rumus Aitken (misalnya setelah memperoleh tiga hasil aproksimasi), kita dapat mempercepat kekonvergenan (accelerating convergence), seolah-olah order of convergence menjadi lebih besar dari 1. Namun, bagaimana cara selang-selingnya?
Menurut Steffensen, rumus Aitken bisa digunakan tiap tiga iterasi fixed-point, yaitu untuk \(p_3\), \(p_6\), \(p_9\), dan seterusnya.
Kita bisa memodifikasi rumus Aitken dengan menggeser indeks \(n\), yaitu menukar \(n\) dengan \(n-3\), untuk mendapatkan rumus iterasi:
\[\hat{p} = p_{n-3} - \frac{\left(p_{n-2} - p_{n-3}\right)^2}{p_{n-1} - 2p_{n-2} + p_{n-3}}\]
dan dalam hal ini, kita juga bisa mendefinisikan \(\Delta_1 = p_{n-2} - p_{n-3}\) dan \(\Delta_2 = p_{n-1} - 2p_{n-2} + p_{n-3}\) untuk mendapatkan bentuk:
\[\hat{p} = p_{n-3} - \frac{(\Delta_1)^2}{(\Delta_2)}\]
def Steffensen(g, p0, tolerance):
# list semua nilai p agar mudah diakses
= [p0]
list_p
# nilai sementara
= tolerance + 1
abs_error
= 1 # penghitung banyaknya iterasi
iterasi while abs_error >= tolerance:
if iterasi % 3 == 0: # untuk kelipatan tiga, gunakan rumus Aitken
= list_p[iterasi - 3] # p_(n-3)
pn_3 = list_p[iterasi - 2] # p_(n-2)
pn_2 = list_p[iterasi - 1] # p_(n-1)
pn_1 = pn_2 - pn_3
Delta1 = pn_1 - 2 * pn_2 + pn_3
Delta2 = pn_3 - (Delta1)**2 / Delta2
pn else: # selain kelipatan 3, gunakan fixed point
= list_p[iterasi - 1]
pn_1 = g(pn_1)
pn
list_p.append(pn)= abs( pn - pn_1 )
abs_error += 1
iterasi
# return bukan hanya p, tetapi juga banyaknya iterasi
return pn, iterasi
from numpy import sin, cos, tan, log, exp, sqrt
= input("Masukkan formula g(x): ")
formula
def g(x):
return eval(formula)
= eval(input("Masukkan titik awal iterasi: "))
starting_point = eval(input("Masukkan batas toleransi: "))
tolerance
= Steffensen(g, starting_point, tolerance)
p_steffensen, i_steffensen
print("Metode Steffensen")
print("Hasil: " + str(p_steffensen))
print("setelah banyaknya iterasi: " + str(i_steffensen))
print("Bandingkan banyaknya iterasi dengan Metode Fixed-Point biasa:")
= FixedPoint(g, starting_point, tolerance)
fixpoint_hasil, fixpoint_tabel print(fixpoint_tabel)
Masukkan formula g(x): 1 + 1/x
Masukkan titik awal iterasi: 2
Masukkan batas toleransi: 10**(-7)
Metode Steffensen
Hasil: 1.618033988749648
setelah banyaknya iterasi: 11
Bandingkan banyaknya iterasi dengan Metode Fixed-Point biasa:
+---------+--------------------+
| iterasi | Aproksimasi |
+---------+--------------------+
| 1 | 1.5 |
| 2 | 1.6666666666666665 |
| 3 | 1.6 |
| 4 | 1.625 |
| 5 | 1.6153846153846154 |
| 6 | 1.619047619047619 |
| 7 | 1.6176470588235294 |
| 8 | 1.6181818181818182 |
| 9 | 1.6179775280898876 |
| 10 | 1.6180555555555556 |
| 11 | 1.6180257510729614 |
| 12 | 1.6180371352785146 |
| 13 | 1.6180327868852458 |
| 14 | 1.618034447821682 |
| 15 | 1.618033813400125 |
| 16 | 1.6180340557275543 |
| 17 | 1.6180339631667064 |
+---------+--------------------+