【每日算法】高速冪
數值的整數次方
實現函數
double Power(double base, int n)
求base的n次方,不得使用庫函數。同一時候不須要考慮大數問題。
Tips
問題本身非常直觀,可是越簡單的題越須要細心思考。包含邊界問題和效率問題。假設不能考慮到以下3點,就無法給出令人愜意的答案:
- 考慮n為負數的情況;
- 考慮base為0的情況。
- 當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!
(●’?’●)
本人水平有限。如文章內容有錯漏之處,敬請各位讀者指出。謝謝!
【每日算法】高速冪