題目:實現函數 double Power(double base, int exponent),求 base 的 exponent 次方。不得使用庫函數,同時不需要考慮大數問題。
通過這道題,瞭解一些不曾注意的知識點:
1、變量命名要合理且明瞭
2、需確保代碼的完整性,從三個角度下手:
1)功能測試:確保主體功能
2)邊界測試:考慮各種邊界值
3)負面測試:考慮各種可能的錯誤輸入
3、代碼高效性,性能測試:考慮代碼的執行效率
4、3種錯誤處理方法:
1)用函數返回值來告知調用者是否出錯
2)當錯誤發生時,設置一個全局變量
3)異常,當函數運行出錯時,拋出一個異常。
對於上述題目,其解答如下:
解決方法一:
只實現了基本功能,即指數 爲正的情況,其他輸入毫無考慮。
double Power0(double base, int exponent)
{
double result = 1.0;
for(int i = 1; i < exponent; i++)
{
result *= base;
}
return result;
}
解決方法二:
考慮代碼的完整性
/**用於判定兩個 double 型數據是否相等,不能直接用 == ,只能用兩者之間的差值在一個很小的範圍內來判斷*/
bool Equal_double(double num1,double num2)
{
if((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))
return true;
else
return false;
}
/**指數爲正的時候*/
double Power_with_unsigned_int(double base,unsigned int exponent)
{
double result = 1.0;
for(unsigned int i = 1; i <= exponent; i++)
{
result *= base;
}
return result;
}
bool g_InvalidInput = false; /**設定一個全局變量來表示無效輸入,變量名要明確*/
double Power1(double base, int exponent)
{
/*考慮基數爲0.0的情況*/
if(Equal_double(base,0.0) && exponent <= 0)
{
g_InvalidInput = true;
return 0.0;
}
else if(Equal_double(base,0.0) && exponent > 0)
return 0.0;
unsigned int absExponent = (unsigned int)(exponent);
if(exponent < 0)
absExponent = (unsigned int)(-exponent);
//cout << "absExponent = " << absExponent << endl;
double result = Power_with_unsigned_int(base,absExponent);
/*指數不爲正的時候,結果倒置*/
if(exponent < 0)
result = 1.0 / result;
return result;
}
解決方法三:
考慮代碼性能,如 2^16 = (2^8)^2 = ((2^4)^2)^2 ........等依次類推,這樣減少了很多重複計算,因此改動 上面的代碼的一部分:
double Power_with_unsigned_int_efficiently(double base, unsigned int exponent)
{
if(exponent == 0)
return 1;
if(exponent == 1)
return base;
double result = Power_with_unsigned_int_efficiently(base, exponent >> 1);
result *= result;
if(exponent & 0x1 == 1) //如果是奇數再乘以一個base,%2==0,等於0表示是偶數
result *= base;
return result;
}
上面的代碼,
1、使用遞歸(思考上面的過程,有助於理解遞歸)
2、用 位運算,左移一位,代表 除以2,用 與運算 代替取餘(%2)來判斷是否是奇數。位運算效率更加高。
通過上面這道題,學到了:
1、簡單問題,更要考慮全面
2、如何判定兩個小數是否相等,不能用“==”,而是要比較兩者之間的差值的絕對值,在一個很小的範圍內。
3、善用 位運算,可以提高效率。
4、不要把遞歸想的太複雜
【對照上面的代碼來看,如果你考慮每一步的遞歸過程(包括怎麼遞歸,怎麼返回上一步),會很複雜,
但是整體來看,就是 一步遞歸 應該乾的事,對於本題來說,就是 result *= result; 其他幾個 if 判斷條件是整體過程需要考慮的】
/*點滴積累,我的一小步O(∩_∩)O~*/