ややプログラム紀行

博士2年のプログラムに関する日記

ニュートン・ラフソン法

前から「sqrt」とかいう平方根を求める関数はどういう仕組みなのか知りたかったんですけど、

今日ある本を読んでたら、「ニュートン・ラフソン法」とかいうのがあったんで、やってみました

double Root(double square){

double denominator = 1;

double numerator = square;

double temp;

temp = 2 * numerator * denominator / square;

numerator = denominator * denominator + numerator * numerator / square;

denominator = temp;

for(int i = 0; i < 5; i++){

temp = 2 * numerator * denominator;

numerator = denominator * denominator * square + numerator * numerator;

denominator = temp;

}

return numerator / denominator;

}

最初の部分はなんというか、簡単にしてます

これがないと値の正確さが少し落ちる

じゃ、値の検証

方法は、各関数で平方根を求めてから、それを2乗するみたいなかんじで

値:10

自作Root:10

sqrt:10

値:100

Root:100.001

sqrt:100

値:1000

Root:1072.25

sqrt:10000

値:10000

Root:31335.4

sqrt:100000

値:100000

Root:2.50833e+006

sqrt:1000000

なんだこのザマは・・・

double型の値の範囲の問題を解決しないと、この関数はしっかりしたものにならなそうですね

ちなみにsqrt関数の方は、doubleの範囲内なら、誤差はありませんでした(多分)

・・・このあと、無駄に工夫せず、本来のニュートン・ラフソン法でプログラムしてみた

long double Root(double square){

long double a = square;

for(int i = 0; i < 8; i++){

a = (a + square / a) / 2;

}

return a;

}

_人人人人人人人人人_

> その結果がこれだよ<

 ̄^Y^Y^Y^Y^Y^Y ̄

値:1000

Root:1000

sqrt:1000

値:10000

Root:10241.9

sqrt:10000

値:100000

Root:223207

sqrt:1000000

こっちの方がいい・・・だと・・・

くそっ!!!!

<実行速度を比べてみた>

10000000回実行して、ミリ秒で計測しました

自作Root関数は、なんとなく速そうな後者のやつで

Root:598

sqrt:277

うわああああああああああ\(^o^)/

これが標準のすごさってやつか

Wikipedia見たら、求根アルゴリズムのページがあったので、それのブレント法とかを使ってるんじゃないですかね

それにしても、改良後のRoot関数より速いってどういうこっちゃ・・・

追記

マリオサンシャインのBGMは神ぞ!!!