関数・メソッド

【JavaScript】平方根を組みこみ関数または自力で計算する方法

更新日:2023/07/12

JavaScriptで平方根を求める方法をお伝えします。

 

組み込み関数を使用する

JavaScriptは組み込みオブジェクトMathに、平方根を計算するsqrt()メソッドが定義されています。

Math.sqrt()の構文

Math.sqrt( x )

xは、isNaN(x)でfalseを返す値、かつ0以上です。

isNaN(x)でfalseを返す値
100 や 200 などの数値
"100" や "200" などの数値文字列
true ⇒ 1、false ⇒ 0
null ⇒ 0
[Symbol.toPrimitive]を適切に実装したオブジェクト

また結果は値を一つ返しますが、符号を反転させたものも平方根の値です。

次のコードは、Math.sqrt()の使用例です。

使用例

console.log( Math.sqrt( 100 ) );   // 結果: 10
console.log( Math.sqrt( "100" ));// 結果: 10
console.log( Math.sqrt( null ) ); // 結果: 0

const obj = {
    value:100,
    [ Symbol.toPrimitive ](hint){
        switch(hint){
            case "string": return this.value.toString();
            case "number": 
            case "default": 
            default:  return this.value;
        }
    }
};
console.log( Math.sqrt( obj ) );// 結果: 10

このメソッドのアルゴリズムは仕様(ECMAScript)で定義されていません。
そのため実装(各ブラウザ、Node.jsなど)で独自に組み込むため、環境によって結果が異なるかもしれません。

 

自力で計算する

平方根はMath.sqrt()を使用すればいいのですが、僕は蛇足的な内容が大好きなので自力で計算してみます。

プログラムに落とし込み可能な平方根の解法は、ニュートン法を利用するとよいらしいです。
htmlでの表記に苦労しそうな数式を理解するのは骨が折れそうなので、結果だけ使います。
興味がある人は、「平方根 ニュートン法」で検索してみてください。
(といいつつ、少し調べてみました)

完成したのが、次のコードです。

const square_root = ((threshold)=>{
    const th = threshold; // 閾値
    return value =>{
        let before_x,x= value;
        do{
            before_x = x;
            x = (before_x + value/before_x) / 2;
        }while( Math.abs( before_x - x ) > th );
        return Math.abs( x );
    };
})(0.00000001);

ニュートン法が、次のコード。

x = (before_x + value/before_x) / 2;

この式で得た変数 x を before_x にセットして、再度同じ式を実行すると求める平方根に収束していきます。
前回の値と計算結果が同じになったら、それ以上収束しないので終了です。

今回は同値ではなくて、閾値で終了判断しています。

この関数を使って、10から30までの平方根を求めてみます。

for( i = 10 ; i <= 30 ; i ++ ) {
    const r1 = square_root(i);
    const r2 = Math.sqrt(i);
    console.log( i,r1 , r2 , r1 - r2 );
}

Math.sqrt()の結果と差分も出力してあります。

次のような結果になりました。


10 3.162277660168379 3.1622776601683795 -4.440892098500626e-16
11 3.3166247903554 3.3166247903554 0
12 3.4641016151377544 3.4641016151377544 0
13 3.6055512754639896 3.605551275463989 4.440892098500626e-16
14 3.7416573867739413 3.7416573867739413 0
15 3.872983346207417 3.872983346207417 0
16 4 4 0
17 4.123105625617661 4.123105625617661 0
18 4.242640687119286 4.242640687119285 8.881784197001252e-16
19 4.358898943540673 4.358898943540674 -8.881784197001252e-16
20 4.47213595499958 4.47213595499958 0
21 4.58257569495584 4.58257569495584 0
22 4.69041575982343 4.69041575982343 0
23 4.795831523312719 4.795831523312719 0
24 4.898979485566356 4.898979485566356 0
25 5 5 0
26 5.0990195135927845 5.0990195135927845 0
27 5.196152422706632 5.196152422706632 0
28 5.291502622129181 5.291502622129181 0
29 5.385164807134505 5.385164807134504 8.881784197001252e-16
30 5.477225575051661 5.477225575051661 0

ほぼ、同じ結果ですね。

 

べき乗を使用する

実はもっと簡単な方法がありました。

√aは、aの2分の1乗と同値です。
そのためJavaScriptのべき乗演算子を使って計算できます。

べき乗による平方根演算

√a = a ** (1/2)

この方法を使って、10から30までの平方根を求めてみます。

for( i = 10 ; i <= 30 ; i ++ ) {
    const r1 = i ** 0.5;
    const r2 = Math.sqrt(i);
    console.log( i,r1 , r2 , r1 - r2 );
}

結果は次のようになります。

10 3.1622776601683795 3.1622776601683795 0
11 3.3166247903554 3.3166247903554 0      
12 3.4641016151377544 3.4641016151377544 0
13 3.605551275463989 3.605551275463989 0  
14 3.7416573867739413 3.7416573867739413 0
15 3.872983346207417 3.872983346207417 0
16 4 4 0
17 4.123105625617661 4.123105625617661 0
18 4.242640687119285 4.242640687119285 0
19 4.358898943540674 4.358898943540674 0
20 4.47213595499958 4.47213595499958 0
21 4.58257569495584 4.58257569495584 0
22 4.69041575982343 4.69041575982343 0
23 4.795831523312719 4.795831523312719 0
24 4.898979485566356 4.898979485566356 0
25 5 5 0
26 5.0990195135927845 5.0990195135927845 0
27 5.196152422706632 5.196152422706632 0
28 5.291502622129181 5.291502622129181 0
29 5.385164807134504 5.385164807134504 0
30 5.477225575051661 5.477225575051661 0

ニュートン法はMath.sqrt()の結果と少し差がありましたが、こちらは同値のようです。

 

ニュートン法

ニュートン法は次の式が基本になっている(らしい)。

xn+1 = xn - f(xn) / f´(xn)

この計算を何度も繰り返すと、求めたい値に収束していく(らしい)。

しかし、数十年も数学から遠ざかっていると、何だこりゃである。

そして、この式から次のような平方根を求める式が導き出される。

x = (before_x + value/before_x) / 2;

とりあえずそのまま採用したけれど、意味不明なまま使うのは気持ち悪いので、少し時間をかけて調べてみました。

f(x) の置き換え

f(x) は、最終的に求めたい値(今回は平方根)がxとして与えられたとき、0になるような式を考えます。

√v のとき、次のような式になります。

f(x) = x - √v = 0
x が √v と同値の時0になるのは当たり前ですね。

次に √ を外すために、それぞれ2乗します。

f(x) = x2 - v = 0

f´(x) の置き換え

f´(x)f(x) の微分です。

次の微分の公式を使用します。
(xn)′=nxn−1

よって、
f(x) = x2 - v
↓ 微分
f´(x) = 2x

となります。

- vが消えました。
微分はxが極小変化したときの変化量です。
なのでxの影響を受けない定数(v)は考慮する必要がないのです。

▶最初の式に当てはめる

f(x)f´(x) を最初の式に当てはめます。

xn+1 = xn - (xn2 - v) / 2xn

累乗すると値が大きくなって、場合によっては数値型の最大値を超えます。
そこで、できるだけ累乗を減らす方向で整理します。

xn+1 = (xn + v / xn) / 2

ここまでわかれば、立方根や累乗根も式を導き出せますね。

ということでいいのだろうか?

更新日:2023/07/12

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。