二分法による 1 変数方程式の解     Last modified: Apr 13, 2004

目的

二分法により一変数間数 f(x)=0 の解を求める。
R には uniroot という関数もあり,これはおもしろい(有効な)使い方ができる。

使用法

bisection(func, lower, upper, ndiv=50, epsilon=1e-14, max.iteration=500)

引数

fun           関数定義
lower         解を探索する範囲の下限値
upper         解を探索する範囲の上限値
ndiv          解を探索する範囲の区分数(50)
epsilon       許容誤差(1e-14)
max.rotation 収束計算上限界数(500)

ソース

インストールは,以下の 1 行をコピーし,R コンソールにペーストする
source("http://aoki2.si.gunma-u.ac.jp/R/src/bisection.R", encoding="euc-jp")

# 分法により一変数間数 f(x)=0 の解を求める
bisection <- function(       func,                                   # 関数 たとえば function(x) (x+6.7)*(x-3.4) のようなもの
                        lower, upper,                           # 解を求める区間
                        ndiv=50,                                # 区間を細区分する個数
                        epsilon=1e-14,                          # 解の許容誤差
                        max.iteration=500)                      # 反復回数の上限
{
        printf <- function(fmt, ...) cat(sprintf(fmt, ...))  # 書式付きの print
        bisec2 <- function(func, lower, upper)                       # 区間の再区分について解を探索する下請け関数
        {
                yl <- func(lower)                            # 区間の左端における関数値
                yu <- func(upper)                            # 区間の右端における関数値
                if (yl*yu > 0) {                                # 同じ符号のとき,この区間には解がない(区間の設定不良)
                        return(1)                               # 戻り値として 1 を返す(利用しなくてもよい)
                }
                for (i in 1:max.iteration) {                    # 繰り返し上限まで収束計算を続ける
                        mid <- (lower+upper)/2                       # そのときの区間の中点の値
                        ym <- func(mid)                              # 中点における関数値
                        if (abs(ym) < epsilon) {             # たまたま解になったら結果を書き出す
                                printf("ans=%g\n", mid)
                                return(0)
                        }
                        else if (yu*ym > 0) {                   # 区間の右端での関数値と符号が同じなら,
                                upper <- mid                 # 中点を区間の右端にする
                                yu <- ym                     # 新しい区間の右端での関数値を設定する
                        }
                        else {                                  # 区間の左端での関数値と符号が同じなら,
                                lower <- mid                 # 中点を区間の左端にする
                                yl <- ym                     # 新しい区間の左端での関数値を設定する
                        }
                        if (abs(upper-lower) < epsilon) {    # 区間幅が誤差範囲内になったら中点を解とする
                                printf("ans=%g\n", (lower+upper)/2)
                                return(0)
                        }
                }
        }

        x <- seq(lower, upper, length.out=ndiv)                      # 区間を細区分して,
        for (i in 1:(ndiv-1)) {                                 # それぞれの細区分に対して,
                bisec2(func, x[i], x[i+1])                      # 二分法により解を求める下請け関数を呼ぶ
        }
}


使用例

bisection(function(x) (x+6.7)*(x-3.4)*(x-sqrt(2)), -10, 10, ndiv=300)		# 3 次方程式の解

出力結果例

> bisection(function(x) (x+6.7)*(x-3.4)*(x-sqrt(2)), -10, 10, ndiv=300)
ans=-6.7
ans=1.41421
ans=3.4


・ 直前のページへ戻る  ・ E-mail to Shigenobu AOKI ( @si.gunma-u.ac.jp )

Made with Macintosh