課程筆記
C6 Open Method (開放法)
C6.1 Simple Fixed-Point Iterative (固定迭代法)
-
步驟:
- 將方程式定義為
之形式。 - 建立一初值
。 - 透過
求新的根,重複進一步確定 中, 與 間的誤差。 - 評估
與 的相對百分誤差是否符合停止點目標決定是否疊代執行。 - 若為發散情況可行的策略:
- 換方程式整理方法(只要符合
的形式就可以) - 換方法
- 換初值
- 換方程式整理方法(只要符合
- 將方程式定義為
-
收斂:
- 當 |g’(x)| < 1 會收斂;而 |g’(x)| > 1 時會發散。
- 當切線(derivative)為正,則誤差疊代情呈單調收斂;若為負 (negative),則誤差疊代呈震盪收斂/發散。
6.2 Newton-Raphson Method (牛頓法)
-
-
步驟:
- 確定 f(x)
- 確定 f’(x)
- 帶入
得到迴圈使用之方程組。 - 通常 10 次以內會有解,如果太久建議中斷調整。
-
牛頓法可能遭遇問題:
- 重根
- 正好接觸斜率接近 0 時可能容易發散導致收斂慢。(當 f’(x)接近 0 時,
可能會變很大) 沒有通用解法,初值的挑選很重要。
6.3 Secant Method (割線法)
原理:
- 已知牛頓法,並且由於:
- 可得:
- 其他步驟與牛頓法相似,但不需要計算導數。
Homework
題目
如上周:
使用固定迭代法、牛頓法與割線法求解此方程式的根。
解題流程
於前次作業 (2024/10/09) 使用 Bisection Method 與 False-Position Method 二種數值方法求解方程式
Simple Fixed-Point Iterative Method
為使用 Simple Fixed-Point Iterative Method 求解方程式
Newton-Raphson Method
為使用 Newton-Raphson Method 求解方程式
Secant Method
為使用 Secant Method 求解方程式
Code
針對本作業撰寫 Golang 代碼如下所示。其中,定義 calcApproxError() 函數計算當前與前次疊代結果的相對誤差,用於判斷 calcSimpleFixedPointIterationMethod()、calcNewtonRaphsonMethod()、calcSecantMethod() 分別使用 Simple Fixed-Point Iterative Method、Newton-Raphson Method 與 Secant Method 三種數值方法尋找根。
-
方法
calcSimpleFixedPointIterationMethod()輸入項包含欲求根之方程式 f 輸入方程式 中的 、數值方法初值 x_l、停止點誤差 epsilon_s。並於函數中參考 Simple Fixed-Point Iterative Method 計算 x_root_new = f(x_root_old) (相當於 ),反覆疊代直至 並於疊代過程中列印過程資訊。其中,為避免式 、 存在無法收斂的情況,定義 times_max = 50 限制疊代次數。 -
方法
calcNewtonRaphsonMethod()輸入項包含欲求根之方程式 f、欲求根方程式的一階導函數 f_prime、數值方法初值 x_l、停止點誤差 epsilon_s。並於函數中參考 Newton-Raphson Method 計算 x_root_new = x_root_old - f(x_root_old) / f_prime(x_root_old) (相當於 ),反覆疊代直至 並於疊代過程中列印過程資訊。 -
方法
calcSecantMethod()輸入項包含欲求根之方程式 f、數值方法初值 x_l 與 x_2 作為初始切線定位點、停止點誤差 epsilon_s。並於函數中參考 Secant Method 計算 x_next := x_root_new - (f(x_root_new)*(x_root_old - x_root_new))/(f(x_root_old)-f(x_root_new)) (相當於 ),反覆疊代直至 並於疊代過程中列印過程資訊。
而 Homework() 函數定義了於本作業中欲求得的方程式 f (相當於式 calcSimpleFixedPointIterationMethod()、calcNewtonRaphsonMethod()、calcSecantMethod() 方法。其中,初值於此定義 x_l = 0.5 (Secant Method 另外定義 x_2 = 0.25),停止點誤差 epsilon_s = 0.005 (相當於 main() 函數呼叫 Homework() 函數執行。
package main
import (
"fmt"
"math"
)
func calcApproxError(Current, Previous float64) float64 {
if Current == 0 {
return math.Inf(1) // 防止除以零
}
return math.Abs((Current - Previous) / Current)
}
func calcSimpleFixedPointIterationMethod(f func(float64) float64, x_1, epsilon_s float64) float64 {
// f is the function to find the root of
// x_1 is the initial guess
times := 1
times_max := 50
x_root_old := x_1
x_root_new := f(x_root_old)
for calcApproxError(x_root_new, x_root_old) > epsilon_s && times <= times_max {
error_appr := calcApproxError(x_root_new, x_root_old)
fmt.Printf("Iteration %2d: x_root = %f, error_appr = %f\n", times, x_root_new, error_appr)
x_root_old = x_root_new
x_root_new = f(x_root_old)
times++
}
if times >= times_max {
fmt.Println("Method failed to converge.")
return math.NaN()
} else {
fmt.Printf("Iteration %2d: x_root = %f, error_appr = %f\n", times, x_root_new, calcApproxError(x_root_new, x_root_old))
}
return x_root_new
}
func calcNewtonRaphsonMethod(f, f_prime func(float64) float64, x_1, epsilon_s float64) float64 {
// f is the function to find the root of
// f_prime is the derivative of f
// x_1 is the initial guess
times := 1
x_root_old := x_1
x_root_new := x_root_old - f(x_root_old)/f_prime(x_root_old)
for calcApproxError(x_root_new, x_root_old) > epsilon_s {
error_appr := calcApproxError(x_root_new, x_root_old)
fmt.Printf("Iteration %2d: x_root = %f, error_appr = %f\n", times, x_root_new, error_appr)
x_root_old = x_root_new
x_root_new = x_root_old - f(x_root_old)/f_prime(x_root_old)
times++
}
fmt.Printf("Iteration %2d: x_root = %f, error_appr = %f\n", times, x_root_new, calcApproxError(x_root_new, x_root_old))
return x_root_new
}
func calcSecantMethod(f func(float64) float64, x_1, x_2, epsilon_s float64) float64 {
// f is the function to find the root of
// x_1 and x_2 are the initial guesses
times := 1
x_root_old := x_1
x_root_new := x_2
x_next := x_root_new - (f(x_root_new)*(x_root_old - x_root_new))/(f(x_root_old)-f(x_root_new))
for calcApproxError(x_root_new, x_root_old) > epsilon_s {
error_appr := calcApproxError(x_root_new, x_root_old)
fmt.Printf("Iteration %2d: x_root = %f, error_appr = %f\n", times, x_root_new, error_appr)
x_root_old = x_root_new
x_root_new = x_next
x_next = x_root_new - (f(x_root_new)*(x_root_old - x_root_new))/(f(x_root_old)-f(x_root_new))
times++
}
fmt.Printf("Iteration %2d: x_root = %f, error_appr = %f\n", times, x_root_new, calcApproxError(x_next, x_root_new))
return x_root_new
}
func Homework() {
f := func(x float64) float64 {
// e^x = 2 - sin(2x)
// f(x) = 2 - sin(2x) - e^x
return 2 - math.Sin(2*x) - math.Exp(x)
}
f_prime := func(x float64) float64 {
// e^x = 2 - sin(2x)
// f(x) = 2 + sin(2x) - e^x
// f'(x) = -2cos(2x) - e^x
return -2*math.Cos(2*x) - math.Exp(x)
}
f_SFPI_1 := func(x float64) float64 {
// e^x = 2 - sin(2x)
// x = ln(2 - sin(2x))
return math.Log(2 - math.Sin(2*x))
}
f_SFPI_2 := func(x float64) float64 {
// e^x = 2 - sin(2x)
// x = 0.5 * arcsin(2 - e^x)
return 0.5 * math.Asin(2 - math.Exp(x))
}
fmt.Println("Simple Fixed Point Iteration Method:")
fmt.Println("x = ln(2 - sin(2x))")
fmt.Printf("Root is: %.10f\n", calcSimpleFixedPointIterationMethod(f_SFPI_1, 0.5, 0.005))
fmt.Println("x = 0.5 * arcsin(2 - e^x)")
fmt.Printf("Root is: %.10f\n", calcSimpleFixedPointIterationMethod(f_SFPI_2, 0.5, 0.005))
fmt.Println()
fmt.Println("Newton-Raphson Method:")
fmt.Printf("Root is: %.10f\n", calcNewtonRaphsonMethod(f, f_prime, 0.5, 0.005))
fmt.Println()
fmt.Println("Secant Method:")
fmt.Printf("Root is: %.10f\n", calcSecantMethod(f, 0.5, 0.25, 0.005))
}
func main() {
Homework()
fmt.Scanln()// Wait for the user
}