首页 > 代码库 > power(乘幂)函数剖析

power(乘幂)函数剖析

近来学习STL,看到power函数的实现感觉挺有趣,记录一下。

1. 一般情况下,我自己要实现乘幂函数会这样实现:

int power(int x,size_t n)
{
    int result = 1;
    while (n--)
        result *= x;
    return result;
}

这样即使实现,这里的时间复杂度和n有关,时间复杂度为0(n)。

2. 看了stl源码实现是这样:

// Returns __x ** __n, where __n >= 0.  _Note that "multiplication"
// is required to be associative, but not necessarily commutative.  
//意思是multiplication要满足结合律,但不需要满足交换律

template <class _Tp, class _Integer, class _MonoidOperation>  
_Tp __power(_Tp __x, _Integer __n, _MonoidOperation __opr)  //这里第三个参数是一个二元操作函数
{
    if (__n == 0)
        return identity_element(__opr);           //返回1
    else 
    {
        while ((__n & 1) == 0)                   //如果n为偶数
        {
            __n >>= 1;
            __x = __opr(__x, __x);
        }

        _Tp __result = __x;
        __n >>= 1;
        while (__n != 0) 
        {
            __x = __opr(__x, __x);
            if ((__n & 1) != 0)                    //如果n为奇数
                __result = __opr(__result, __x);
            __n >>= 1;
        }
        return __result;
    }
}

template <class _Tp, class _Integer>
inline _Tp __power(_Tp __x, _Integer __n)
{
    return __power(__x, __n, multiplies<_Tp>());
}

// Alias for the internal name __power.  Note that power is an extension,
// not part of the C++ standard.

template <class _Tp, class _Integer, class _MonoidOperation>
inline _Tp power(_Tp __x, _Integer __n, _MonoidOperation __opr)   //也可以自定义,传进去一个函数
{
    return __power(__x, __n, __opr);
}

template <class _Tp, class _Integer>
inline _Tp power(_Tp __x, _Integer __n)   //默认情况下是乘幂
{
    return __power(__x, __n);
}

这里:当n为偶数时,X^n=(X^2)^(2/n),此时看2/n是否还是偶数,如果是则继续,否则,转向n是奇数的情况;

           当n为奇数时,X^n=X*X^(n-1);

例如计算5^6=(5^2)^3,也就是计算25^3。

这种情况和第三种情况类似,只是当n开始为偶数时,比第三种方法的效率更高,n为奇数时,和第三种方法时间复杂度一样。

3. 看了还有一种实现,和stl源码差不多,只是表示更简洁,和第二种情况相比效率会差点:

int power(int x, size_t n)
{
    if(n == 0)
        return 1;
    int result = 1;
    while(n)
    {
        if(n & 1)                    //n为奇数时
            result *= x;            
        n >>= 1;
        x *= x;                 
    }
}

如计算5^6是6化为二进制为0110,所以这里5^6=5^2*5^4,这里时间复杂度为0((log2n)+1)

power(乘幂)函数剖析