割線法; Secant Method
概要
割線法は関数値が0を通る点を求める求根アルゴリズムの一つ。領域の端2点を通る直線とx軸との交点を新たな領域の端とすることを繰り返し根を求める。
挟み撃ち法と似ているが、両端を更新していくところが異なる。
アルゴリズム
\(f(x)=0\)となる\(x\)を求める。
・初期値
-根を含む領域\([x_0, x_1]\)を設定する。
・収束計算
-領域の端2点を通る直線とx軸との交点を求める。
\(\quad \displaystyle x_n = \frac{x_{n-2} f(x_{n-1})-x_{n-1} f(x_{n-2})} {f(x_{n-1}) - f(x_{n-2})} \)
留意点
十分に収束すると\(f(x_{n-1}) - f(x_{n-2})\)が0に近づくため、計算誤差が大きくなる。そのためあまり精度が出ない。
他の求根アルゴリズムに切り替える必要がある
ソースコード
namespace RootFindingMethod {
/// <summary>割線法</summary>
/// <remarks>f(x)=0となるxを求める</remarks>
public static class SecantMethod {
/// <summary>求根</summary>
/// <param name="func">f(x)=0となる関数f(x)</param>
/// <param name="xa">求根範囲</param>
/// <param name="xb">求根範囲</param>
/// <param name="precision_level">精度レベル</param>
/// <remarks>f(xa), f(xb)は異符号である必要がある</remarks>
public static double Execute(Func<double, double> func, double xa, double xb, int precision_level) {
double a = func(xa), b = func(xb), c, xc = xa;
if((a > 0 && b > 0) || (a < 0 && b < 0)) {
throw new ArgumentException($"Invalid Range {nameof(xa)}, {nameof(xb)}");
}
while(precision_level > 0 && a != b) {
xc = (xb * a - xa * b) / (a - b);
c = func(xc);
xb = xa;
b = a;
xa = xc;
a = c;
precision_level--;
}
return xc;
}
}
}
単体テスト
namespace RootFindingMethod.Tests {
[TestClass()]
public class SecantMethodTests {
[TestMethod()]
public void ExecuteTest1() {
Func<double, double> func = (x) => x * x - 2;
double v = SecantMethod.Execute(func, 0, 2, 20);
Assert.AreEqual(v, Math.Sqrt(2), 1e-14);
}
[TestMethod()]
public void ExecuteTest2() {
Func<double, double> func = (x) => x * x - 2;
double v = SecantMethod.Execute(func, 2, 0, 20);
Assert.AreEqual(v, Math.Sqrt(2), 1e-14);
}
}
}
関連項目
ニュートンラフソン法
二分法
挟み撃ち法