[leetcode] 50. Pow(x, n)の「二分累乗法の効率化」はなぜ速いのか

記事
IT・テクノロジー

 [leetcode] 50. Pow(x, n)の「二分累乗法の効率化」はなぜ速いのか

const myPow = function(x, n) {
    function binaryExp(x, n){

        if(n === 0) return 1;
        if(n < 0) return 1 / binaryExp(x, -1 * n);

        if(n % 2 === 1){
            return x * binaryExp(x * x, (n - 1) / 2);
        } else {
            return binaryExp(x * x, n / 2);
        }
    }
    return binaryExp(x, n)
};


このmyPow関数は、数値xをn乗した結果を効率的に計算するためのものです。これは「二分累乗法」という手法を使っています。


#### 基本ケース:
nが0の場合、どんな数でも0乗は1なので、1を返します。

nが負の場合、1 / binaryExp(x, -n)で計算します。これは正の指数で計算して、その結果を逆数にするためです。

#### 再帰的な計算:
nが奇数なら、x * binaryExp(x * x, (n - 1) / 2)で計算します。xを一度掛けてから、nを半分にします。
nが偶数なら、binaryExp(x * x, n / 2)で計算します。nを半分にして計算を続けます。
例:
myPow(2, 10)の場合、結果は1024になります。このように、指数が大きくても高速に計算できます。


### nが負の場合、1 / binaryExp(x, -n)で計算します。これは正の指数で計算して、その結果を逆数にするため?

nが負の場合、例えばx^-3のようなケースを考えてみましょう。

例としてmyPow(2, -3)を考えると:

#### 計算手順:
nが負なので、nを正にして計算します。この場合、n = -3が正の3に変わります。
まず、2^3を計算します。2^3 = 8ですね。
次に、その結果を逆数にします。1 / 8 = 0.125になります。
つまり、2^-3という計算は、「まず2を正の指数で計算し、その結果を逆数にする」という流れで行われます。

なぜこうするのか?

負の指数は数学的に「逆数を取る」という意味を持ちます。x^-nは1 / x^nと同じです。例えば2^-3は、1 / 2^3、すなわち1 / 8です。

このように、まず正の指数で普通に計算してから、その結果の逆数を取ることで、負の指数も正しく計算できます。

### なぜこの関数が速いのか

このmyPow関数が速い理由は、「二分累乗法」(Exponentiation by Squaring)を使っているからです。この方法では、計算の回数を大幅に減らすことができます。

#### 通常の計算方法との違い
通常、x^nを計算するには、xをn回掛け算します。例えば、2^10を計算する場合、2 * 2 * 2 * ... * 2を10回行います。これは大きな指数では非常に多くの掛け算が必要になります。

二分累乗法の効率化
二分累乗法では、以下のように計算を分割して進めます:

`nが偶数の場合:x^n = (x^2)^(n/2)`

`nが奇数の場合:x^n = x * (x^2)^((n-1)/2)`

この方法では、毎回指数を半分にして計算するため、掛け算の回数が大幅に減ります。

#### 具体例:2^10の場合
2^10は偶数なので、(2^2)^5、つまり4^5に変換します。
4^5は奇数なので、4 * (4^2)^2に変換し、次に16^2を計算します。
最終的に16^2 = 256なので、4 * 256 = 1024という結果が得られます。
これにより、10回の掛け算をする代わりに、わずか4回の掛け算で済むようになります。指数が大きくなるほど、この効率の差はさらに大きくなります。










サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す