1. 程式人生 > >【每日算法】高速冪

【每日算法】高速冪

-1 addclass function -a con 偶數 斐波那契數列 設置 復雜

數值的整數次方

實現函數

double Power(double base, int n) 

求base的n次方,不得使用庫函數。同一時候不須要考慮大數問題。

Tips

問題本身非常直觀,可是越簡單的題越須要細心思考。包含邊界問題和效率問題。假設不能考慮到以下3點,就無法給出令人愜意的答案:

  1. 考慮n為負數的情況;
  2. 考慮base為0的情況。
  3. 當n較大時,怎樣保證效率?

分析

針對上面3個問題,我們逐一解答:

1.在計算的時候。我們統一計算base的 abs(n)次方,最後假設是負數。答案應該取倒數;

2.假設base為0。則它不能做分母。此時若n<0。則我們應該返回錯誤信息。

關於返回錯誤信息,一般有以下方法:

  • 通過返回值;
  • 通過全局變量。
  • 拋出異常。

在這裏,我們註意到返回值本身能夠取隨意值,所以不能單純靠返回值;假設僅設置全局變量,那麽每次計算之後都有檢查,比較麻煩;我們能夠選擇返回值+全局變量的形式來返回錯誤:

假設有錯,返回0,且設置全局變量。

3.當n較大時。可使用高速冪:

若n為偶數, base^n = base^(n/2) * base^(n/2);
若n為奇數。 base^n = base * base^((n-1)/2) * base^((n-1)/2);

解答

以下是Power函數:

bool error = false;
double
Power(double base, int n) { error = false; if (equal(base, 0.0) && n < 0) { error = true; return 0.0; } unsigned int absN = (unsigned int)n; if (n < 0) absN = (unsigned int)(-n); double result = PowerWithUnsignedN(base, absN); if (n < 0
) result = 1.0/result; return result; }

Notice:對於小數,推斷是否相等不能直接用 == ,而應該計算兩者的差值在一個精度範圍內:

bool equal(int num1, int num2)
{
    if ((num1-num2) > -0.0000001 && (num1-num2) < 0.0000001)
        return true;
    else
        return false;
}

以下是核心的高速冪的遞歸版本號:

double PowerWithUnsignedN(double base, unsigned int n)
{
    if (0 == n) return 1;
    if (1 == n) return base;
    double res = PowerWithUnsignedN(base, n>>1);
    res *= res;
    if (n & 1) //n為奇數
        res *= base;
    return res;
}

普通情況下,以上代碼已經非常完美了~

只是假設你更加追求效率,想必遞歸版本號並不能滿足你。那麽能夠試一試以下的非遞歸版本號:

double PowerWithUnsignedN(double base, unsigned int n)
{
    double res = 1.0;
    while (n > 0)
    {
        if (n & 1)
            res *= base;
        base *= base;
        n >>= 1;
    }
    return res;
}

關於高速冪,我們經常常使用來做高速冪取模等,略微復雜一點,我們能夠用它來做矩陣的高速冪。原理是一樣的,僅僅是操作的對象是一個矩陣而不是一個數(矩陣高速冪以求斐波那契數列較為著名。此處暫不展開。後面會開專題寫斐波那契數列。有興趣的讀者能夠先自行查找相關資料)。

每天進步一點點,Come on!
(●’?’●)


本人水平有限。如文章內容有錯漏之處,敬請各位讀者指出。謝謝!

【每日算法】高速冪