fixedpoint <- function(ftn, x0, tol = 1e-9, max.iter = 100) {
xold <- x0
xnew <- ftn(xold)
iter <- 1
cat("Iterasi ke-", iter, ": x =", xnew, "\n")
while ((abs(xnew - xold) > tol) && (iter < max.iter)) {
xold <- xnew
xnew <- ftn(xold)
iter <- iter + 1
cat("Iterasi ke-", iter, ": x =", xnew, "\n")
}
if (abs(xnew - xold) > tol) {
cat("Gagal konvergen\n")
return(NULL)
} else {
cat("Konvergen!\n")
return(xnew)
}
}Praktikum Pemrograman Statistika
Dari Dugaan ke Konvergen: Eksplorasi Algoritma Root Finding
Pendahuluan
Menemukan akar persamaan dapat diibaratkan seperti mencari titik keseimbangan dalam sebuah sistem yang dinamis. Ada saat di mana kita sudah dekat dengan solusi, namun setiap langkah perbaikan justru membawa kita menjauh; ada pula ketika satu dugaan sederhana justru menuntun kita menuju konvergensi yang stabil. Proses inilah yang menjadi inti dari analisis numerik: mendekati kebenaran secara bertahap melalui serangkaian iterasi yang terukur.
Masalah pencarian akar persamaan \(f(x)=0\) muncul di berbagai bidang ilmu, mulai dari estimasi parameter statistika hingga optimisasi fungsi kompleks. Karena tidak semua persamaan memiliki solusi analitik, pendekatan numerik digunakan untuk memperoleh nilai hampiran yang cukup akurat. Pendekatan ini bergantung pada gagasan sederhana: menebak, mengevaluasi, memperbaiki, dan mengulang — hingga perbedaan antara dua langkah berturut-turut menjadi sangat kecil.
Empat algoritma utama yang digunakan dalam eksplorasi ini adalah Fixed-Point Iteration, Newton-Raphson, Secant, dan Bisection. Masing-masing menawarkan filosofi berbeda: Fixed-Point yang sederhana namun rentan gagal konvergen; Newton-Raphson yang cepat dan elegan tetapi bergantung pada turunan; Secant yang praktis tanpa turunan eksplisit; dan Bisection yang mungkin lambat namun menjamin kepastian hasil. Keempatnya menunjukkan bahwa tidak ada satu cara tunggal untuk mencapai akar — hanya strategi yang lebih atau kurang efisien tergantung konteksnya.
Melalui implementasi algoritma dalam bahasa R, proses pencarian akar ini tidak hanya menjadi latihan komputasi, tetapi juga sarana untuk memahami bagaimana konsep konvergensi, kesalahan, dan efisiensi bekerja secara nyata. Seperti halnya mencari keseimbangan dalam kehidupan, setiap metode mengajarkan bahwa ketepatan hasil sering kali ditentukan oleh cara kita melangkah, bukan sekadar seberapa cepat kita tiba di tujuan.
Metode Fixed-Point
Fixed-Point merupakan salah satu pendekatan paling dasar dalam pencarian akar persamaan. Metode ini tidak secara langsung menyelesaikan persamaan \(f(x)=0\), tetapi mengubah bentuk persamaan tersebut menjadi \(x=g(x)\), kemudian mencari titik tetap (fixed point) dari fungsi \(g\). Titik tetap ini adalah nilai \(x\) yang ketika disubstitusikan ke dalam \(g(x)\), menghasilkan dirinya sendiri: \(g(x)=x\).
Proses iteratif dimulai dari dugaan awal \(x_0\), kemudian dihitung \(x_1=g(x_0)\), \(x_2=g(x_1)\), dan seterusnya hingga perubahan antar dua iterasi cukup kecil, yaitu:
\[ |x_{n+1} - x_n| < \varepsilon \]
Namun, meskipun sederhana, metode ini memiliki keterbatasan: tidak semua bentuk \(g(x)\) akan menghasilkan konvergensi. Pemilihan fungsi \(g(x)\) dan nilai awal yang tidak tepat dapat menyebabkan iterasi gagal mencapai titik tetap.
Secara umum, metode Fixed-Point mengikuti alur iteratif berikut:
- Tentukan nilai awal tebakan \(x_0\).
- Untuk setiap iterasi ke-\(n\), hitung nilai baru \(x_{n+1} = g(x_n)\).
- Periksa apakah selisih antara dua iterasi berturut-turut cukup kecil: \(|x_{n+1} - x_n| < \varepsilon\). Jika ya, iterasi dihentikan — solusi telah konvergen.
- Jika tidak, perbarui nilai: \(x_n \leftarrow x_{n+1}\) dan lanjutkan ke langkah 2.
- Proses iterasi juga akan dihentikan jika jumlah langkah melebihi batas maksimum yang ditentukan (misalnya 100 iterasi).
Berikut adalah implementasi fungsi fixedpoint() dalam bahasa R. Fungsi ini menerima tiga argumen utama: fungsi iterasi g(x), dugaan awal x0, serta toleransi kesalahan (tol) dan batas maksimum iterasi (max.iter). Proses iteratif akan berjalan hingga selisih antar iterasi cukup kecil atau batas iterasi tercapai.
Fungsi ini akan mencetak nilai hasil pada setiap iterasi, dan mengembalikan akar hampiran jika proses berhasil konvergen. Jika selisih antar iterasi tidak pernah cukup kecil dalam batas iterasi yang ditentukan, maka fungsi akan menghentikan proses dan menampilkan pesan kegagalan konvergensi. Setelah fungsi siap digunakan, kita dapat mengujinya pada beberapa fungsi iteratif \(g(x)\) yang berbeda.
Kita akan menguji implementasi metode Fixed-Point pada fungsi berikut:
\[ g(x) = \exp(\exp(-x)) \]
Fungsi ini dapat digunakan dalam bentuk iteratif karena bersifat cukup kontraktif di sekitar titik tetap. Nilai awal yang digunakan adalah \(x_0=2\), dan toleransi kesalahan ditetapkan sebesar \(\varepsilon = 10^{-6}\).
f1 <- function(x) exp(exp(-x))
fixedpoint(f1, 2, tol = 1e-6)Iterasi ke- 1 : x = 1.144921
Iterasi ke- 2 : x = 1.374719
Iterasi ke- 3 : x = 1.287768
Iterasi ke- 4 : x = 1.317697
Iterasi ke- 5 : x = 1.307022
Iterasi ke- 6 : x = 1.310783
Iterasi ke- 7 : x = 1.309452
Iterasi ke- 8 : x = 1.309922
Iterasi ke- 9 : x = 1.309756
Iterasi ke- 10 : x = 1.309815
Iterasi ke- 11 : x = 1.309794
Iterasi ke- 12 : x = 1.309802
Iterasi ke- 13 : x = 1.309799
Iterasi ke- 14 : x = 1.3098
Konvergen!
[1] 1.3098
Iterasi berhenti pada langkah ke-14, menunjukkan bahwa nilai-nilai yang dihasilkan sudah cukup dekat satu sama lain. Nilai hampiran akar adalah sekitar 1.3098, dan selisih antar iterasi sudah lebih kecil dari toleransi yang ditentukan.
Fungsi ini menunjukkan sifat konvergen dari metode Fixed-Point karena bentuknya memenuhi syarat kontraktif dalam interval tertentu. Dengan dugaan awal yang cukup dekat, iterasi berjalan stabil menuju titik tetap.
Fungsi berikut digunakan untuk mengilustrasikan kasus ketika metode Fixed-Point gagal mencapai konvergensi:
\[ g(x) = x + \log(x) - e^{-x} \]
Dugaan awal tetap digunakan pada \(x_0=2\), dan toleransi kesalahan ditetapkan sebesar \(\varepsilon = 10^{-6}\), dengan batas maksimum iterasi sebanyak 20 langkah.
f2 <- function(x) x + log(x) - exp(-x)
fixedpoint(f2, 2, tol = 1e-6, max.iter = 20)Iterasi ke- 1 : x = 2.557812
Iterasi ke- 2 : x = 3.41949
Iterasi ke- 3 : x = 4.616252
Iterasi ke- 4 : x = 6.135946
Iterasi ke- 5 : x = 7.947946
Iterasi ke- 6 : x = 10.02051
Iterasi ke- 7 : x = 12.3251
Iterasi ke- 8 : x = 14.83673
Iterasi ke- 9 : x = 17.53383
Iterasi ke- 10 : x = 20.39797
Iterasi ke- 11 : x = 23.4134
Iterasi ke- 12 : x = 26.56671
Iterasi ke- 13 : x = 29.84637
Iterasi ke- 14 : x = 33.24243
Iterasi ke- 15 : x = 36.74626
Iterasi ke- 16 : x = 40.3503
Iterasi ke- 17 : x = 44.04789
Iterasi ke- 18 : x = 47.83317
Iterasi ke- 19 : x = 51.70089
Iterasi ke- 20 : x = 55.64637
Gagal konvergen
NULL
Metode Newton-Raphson
Metode Newton-Raphson adalah salah satu pendekatan paling populer dan efisien untuk mencari akar persamaan \(f(x)=0\). Berbeda dengan Fixed-Point Iteration yang bergantung pada bentuk iteratif khusus, metode ini secara langsung memanfaatkan informasi turunan pertama dari fungsi untuk memperbaiki dugaan akar.
Secara geometris, Newton-Raphson menggunakan garis singgung (tangen) dari kurva \(f(x)\) pada titik \(x_n\), dan menentukan perpotongannya dengan sumbu-\(x\) sebagai nilai dugaan berikutnya \(x_{n+1}\). Rumus iterasinya dinyatakan sebagai:
\[ x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} \]
Proses ini akan terus diulang hingga nilai \(|x_{n+1} - x_n|\) cukup kecil, atau hingga jumlah iterasi mencapai batas maksimum.
Berikut adalah langkah-langkah umum dalam metode Newton-Raphson:
- Tentukan tebakan awal \(x_0\).
- Hitung nilai fungsi dan turunannya di titik tersebut: \(f(x_n)\) dan \(f'(x_n)\).
- Hitung nilai iterasi baru: \[ x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} \]
- Periksa apakah \(|x_{n+1}-x_n|<\varepsilon\). Jika ya, iterasi dihentikan.
- Jika tidak, perbarui \(x_n \leftarrow x_{n+1}\) dan ulangi langkah 2.
- Iterasi dihentikan jika batas jumlah langkah maksimum tercapai.
Di R, kita dapat mengimplementasikan metode Newton-Raphson dengan fungsi newtonraphson(). Fungsi ini menerima sebuah fungsi ftn yang mengembalikan nilai dari \(f(x)\) dan \(f'(x)\) dalam bentuk vektor panjang 2.
newtonraphson <- function(ftn, x0, tol = 1e-5, max.iter = 100) {
x <- x0
fx <- ftn(x)
iter <- 0
while ((abs(fx[1]) > tol) && (iter < max.iter)) {
x <- x - fx[1] / fx[2]
fx <- ftn(x)
iter <- iter + 1
cat("Iterasi ke-", iter, ": x =", x, "\n")
}
if (abs(fx[1]) > tol) {
cat("Gagal konvergen\n")
return(NULL)
} else {
cat("Konvergen!\n")
return(x)
}
}Kita akan menguji implementasi metode Newton-Raphson untuk fungsi berikut:
\[ f(x) = \log(x) - e^{-x} \] \[ f'(x) = \frac{1}{x} + e^{-x} \]
Dugaan awal yang digunakan adalah \(x_0=3\), dan toleransi kesalahan ditetapkan sebesar \(\varepsilon=10^{-5}\). Implementasi fungsi dan turunannya dikemas dalam bentuk satu fungsi R yang mengembalikan dua elemen: nilai fungsi dan nilai turunannya.
f_logexp <- function(x) {
fx <- log(x) - exp(-x)
dfx <- 1/x + exp(-x)
return(c(fx, dfx))
}
newtonraphson(f_logexp, x0 = 3, tol = 1e-5)Iterasi ke- 1 : x = 0.2624136
Iterasi ke- 2 : x = 0.7224658
Iterasi ke- 3 : x = 1.156032
Iterasi ke- 4 : x = 1.299908
Iterasi ke- 5 : x = 1.309759
Iterasi ke- 6 : x = 1.3098
Konvergen!
[1] 1.3098
Metode Secant
Metode Secant merupakan pengembangan dari pendekatan Newton-Raphson, namun tidak memerlukan turunan eksplisit dari fungsi. Sebagai gantinya, metode ini menggunakan pendekatan selisih terbagi (finite difference) untuk mengaproksimasi turunan.
Secara matematis, turunan \(f'(x)\) pada Newton-Raphson digantikan oleh:
\[ f'(x_n) \approx \frac{f(x_n) - f(x_{n-1})}{x_n - x_{n-1}} \]
Dengan menggantikan ini ke dalam rumus iterasi Newton-Raphson, diperoleh formula metode Secant:
\[ x_{n+1} = x_n - f(x_n) \cdot \frac{x_n - x_{n-1}}{f(x_n) - f(x_{n-1})} \]
Metode ini sangat berguna ketika fungsi yang dianalisis tidak memiliki bentuk turunan yang mudah dihitung atau tidak dapat diturunkan secara analitik.
Langkah-langkah algoritma metode Secant adalah:
- Tentukan dua dugaan awal: \(x_0\) dan \(x_1\).
- Hitung nilai fungsi pada kedua titik: \(f(x_0)\), \(f(x_1)\).
- Hitung nilai \(x_2\) menggunakan formula Secant: \[ x_2 = x_1 - f(x_1) \cdot \frac{x_1 - x_0}{f(x_1) - f(x_0)} \]
- Perbarui nilai: $x_0 x_1 $, $ x_1 x_2 $.
- Ulangi langkah 2–4 sampai konvergen atau iterasi maksimum tercapai.
Fungsi secant() berikut ini mengimplementasikan algoritma di atas:
secant <- function(ftn, x0, x1, tol = 1e-9, max.iter = 100) {
xa <- x0
xb <- x1
fxa <- ftn(xa)
fxb <- ftn(xb)
iter <- 0
while ((abs(xb - xa) > tol) && (iter < max.iter)) {
xt <- fxb * ((xb - xa) / (fxb - fxa))
xc <- xb - xt
cat("Iterasi ke-", iter + 1, ": x =", xc, "\n")
xa <- xb
xb <- xc
fxa <- ftn(xa)
fxb <- ftn(xb)
iter <- iter + 1
}
if (abs(xb - xa) > tol) {
cat("Gagal konvergen\n")
return(NULL)
} else {
cat("Konvergen!\n")
return(xb)
}
}Kita akan menguji metode Secant menggunakan fungsi yang sama seperti sebelumnya:
\[ f(x) = \log(x) - e^{-x} \]
Nilai awal yang digunakan adalah \(x_0 = 1\) dan \(x_1 = 2\), dengan toleransi kesalahan sebesar \(\varepsilon = 10^{-6}\).
f_secant <- function(x) log(x) - exp(-x)
secant(f_secant, 1, 2, tol = 1e-6)Iterasi ke- 1 : x = 1.39741
Iterasi ke- 2 : x = 1.285476
Iterasi ke- 3 : x = 1.310677
Iterasi ke- 4 : x = 1.309808
Iterasi ke- 5 : x = 1.3098
Iterasi ke- 6 : x = 1.3098
Konvergen!
[1] 1.3098
Metode Bisection
Metode Bisection merupakan metode numerik paling sederhana dan paling aman untuk mencari akar persamaan ( f(x) = 0 ). Tidak seperti metode Newton-Raphson atau Secant yang bersifat terbuka dan iteratif dengan tebakan, metode ini menggunakan pendekatan interval tertutup dan menjamin konvergensi jika fungsi memenuhi syarat tertentu.
Syarat utama yang harus dipenuhi adalah:
\[ f(x_L) \cdot f(x_R) < 0 \]
Artinya, fungsi harus memiliki tanda yang berlawanan di kedua ujung interval ( [x_L, x_R] ), sehingga menjamin terdapat paling tidak satu akar di antara keduanya (berdasarkan Teorema Nilai Perantara).
Langkah-langkah metode Bisection adalah:
- Tentukan dua titik awal \(x_L\) dan \(x_R\) sehingga \(f(x_L) \cdot f(x_R) < 0\).
- Hitung titik tengah: \[ x_M = \frac{x_L + x_R}{2} \]
- Evaluasi \(f(x_M)\):
- Jika \(f(x_M) = 0\), maka akar telah ditemukan.
- Jika \(f(x_L) \cdot f(x_M) < 0\), set \(x_R \leftarrow x_M\).
- Jika \(f(x_M) \cdot f(x_R) < 0\), set \(x_L \leftarrow x_M\).
- Ulangi langkah 2–3 hingga:
- Selisih antar batas \(|x_R - x_L| < \varepsilon\), atau
- Maksimum iterasi tercapai.
bisection <- function(ftn, xL, xR, tol = 1e-6, max.iter = 100) {
fL <- ftn(xL)
fR <- ftn(xR)
if (fL * fR > 0) {
stop("f(xL) * f(xR) harus bernilai negatif. Tidak ada jaminan akar di dalam interval.")
}
iter <- 0
while ((abs(xR - xL) > tol) && (iter < max.iter)) {
xM <- (xL + xR) / 2
fM <- ftn(xM)
cat("Iterasi ke-", iter + 1, ": x =", xM, "\n")
if (fM == 0) {
return(xM)
} else if (fL * fM < 0) {
xR <- xM
fR <- fM
} else {
xL <- xM
fL <- fM
}
iter <- iter + 1
}
if (abs(xR - xL) <= tol) {
cat("Konvergen!\n")
return((xL + xR) / 2)
} else {
cat("Gagal konvergen dalam batas iterasi.\n")
return(NULL)
}
}Metode Bisection diuji pada fungsi yang sama seperti sebelumnya:
\[ f(x) = \log(x) - e^{-x} \]
Fungsi ini bersifat kontinu dan memiliki tanda berlawanan pada interval \([1, 2]\), karena:
- \(f(1) = \log(1) - e^{-1} = -0.3679 < 0\)
- \(f(2) = \log(2) - e^{-2} = 0.5560 > 0\)
Hal ini memenuhi syarat metode Bisection untuk menjamin keberadaan akar dalam interval tersebut.
f_bisect <- function(x) log(x) - exp(-x)
bisection(f_bisect, 1, 2, tol = 1e-6)Iterasi ke- 1 : x = 1.5
Iterasi ke- 2 : x = 1.25
Iterasi ke- 3 : x = 1.375
Iterasi ke- 4 : x = 1.3125
Iterasi ke- 5 : x = 1.28125
Iterasi ke- 6 : x = 1.296875
Iterasi ke- 7 : x = 1.304688
Iterasi ke- 8 : x = 1.308594
Iterasi ke- 9 : x = 1.310547
Iterasi ke- 10 : x = 1.30957
Iterasi ke- 11 : x = 1.310059
Iterasi ke- 12 : x = 1.309814
Iterasi ke- 13 : x = 1.309692
Iterasi ke- 14 : x = 1.309753
Iterasi ke- 15 : x = 1.309784
Iterasi ke- 16 : x = 1.309799
Iterasi ke- 17 : x = 1.309807
Iterasi ke- 18 : x = 1.309803
Iterasi ke- 19 : x = 1.309801
Iterasi ke- 20 : x = 1.3098
Konvergen!
[1] 1.3098
Ringkasan Perbandingan Metode
| Metode | Deskripsi | Kelebihan | Kekurangan | Hal yang Perlu Diperhatikan | Kapan Digunakan |
|---|---|---|---|---|---|
| Fixed-Point | Iterasi pada bentuk \(x = g(x)\) untuk mencari titik tetap | Implementasi sederhana, tidak perlu turunan | Tidak selalu konvergen, bergantung pada sifat kontraktif fungsi | Pastikan \(|g'(x)| < 1\) di sekitar akar (kontraktif) | Saat bentuk fungsi \(g(x)\) diketahui dan divergensi tidak menjadi masalah |
| Newton-Raphson | Menggunakan turunan: \(x_{n+1} = x_n - \frac{f(x)}{f'(x)}\) | Konvergensi sangat cepat (kuadratik) jika dekat akar | Butuh \(f'(x)\), sensitif terhadap tebakan awal, bisa divergen | Turunan harus tersedia dan tidak mendekati nol | Jika turunan tersedia dan tebakan awal cukup dekat akar |
| Secant | Aproksimasi turunan menggunakan dua titik sebelumnya | Tidak perlu turunan eksplisit, lebih cepat dari Bisection | Tidak selalu konvergen, perlu dua tebakan awal, bisa tidak stabil | Pilih dua titik awal yang cukup dekat dan menghasilkan \(f(x)\) berbeda | Saat tidak ada turunan, tapi ingin pendekatan yang lebih efisien dari Bisection |
| Bisection | Membagi dua interval dengan tanda fungsi berlawanan | Selalu konvergen jika syarat dipenuhi, sangat stabil | Konvergensi lambat (linear), hanya untuk satu akar dalam interval | Harus ada \(f(x_L) \cdot f(x_R) < 0\), fungsi kontinu | Jika fungsi sederhana, tidak diketahui turunannya, dan stabilitas lebih penting |