本文參考自《劍指offer》一書,代碼采用Java語言。
題目
實現函數double Power(double base, int exponent),求base的exponent次方。不得使用庫函數,同時不需要考慮大數問題。
思路
這道題很容易實現,但需要注意以下陷阱:1)0的負數次方不存在;2)0的0次方沒有數學意義;3)要考慮exponent為負數的情況。所以可以對exponent進行分類討論,在對base是否為0進行討論。
測試用例
指數和底數都分別設置為正負數和0.
完整Java代碼
(含測試代碼)
/**
*
* @Description 面試題16:數值的整數次方
*
* @author yongh
* @date 2018年9月17日 下午5:17:35
*/
// 題目:實現函數double Power(double base, int exponent),求base的exponent
// 次方。不得使用庫函數,同時不需要考慮大數問題。
public class Power {
boolean IsInvalid = false;//用全局變量標記是否出錯
public double power(double base, int exponent) {
IsInvalid = false;
double result; // double類型
if (exponent > 0) {
result = powerCore(base, exponent);
} else if (exponent < 0) {
if (base == 0) {
IsInvalid = true; //0的負數次方不存在
return 0;
}
result = 1 / powerCore(base, -exponent);
} else {
return 1; //這里0的0次方輸出為1
}
return result;
}
private double powerCore(double base, int exponent) {
if (exponent == 1)
return base;
if (exponent == 0)
return 1;
double result = powerCore(base, exponent >> 1);
result *= result;
if ((exponent & 0x1) == 1)
result *= base;
return result;
}
// ========測試代碼========
void test(String testName, double base, int exponent, double expected, boolean expectedFlag) {
if (testName != null)
System.out.print(testName + ":");
if (power(base, exponent) == expected && IsInvalid == expectedFlag) {
System.out.println("passed.");
} else {
System.out.println("failed.");
}
}
void test1() {
test("test1", 0, 6, 0, false);
}
void test2() {
test("test2", 0, -6, 0, true);
}
void test3() {
test("test3", 0, 0, 1, false);
}
void test4() {
test("test4", 2, 6, 64, false);
}
void test5() {
test("test5", 2, -3, 0.125, false);
}
void test6() {
test("test6", 5, 0, 1, false);
}
void test7() {
test("test7", -2, 6, 64, false);
}
public static void main(String[] args) {
Power demo = new Power();
demo.test1();
demo.test2();
demo.test3();
demo.test4();
demo.test5();
demo.test6();
demo.test7();
}
}
test1:passed.
test2:passed.
test3:passed.
test4:passed.
test5:passed.
test6:passed.
test7:passed.
非遞歸實現乘方:
上面的powerCore()方法可改寫如下:
/**
* 非遞歸實現乘方
*/
private double powerCore2(double base, int exponent) {
double result=1;
while(exponent!=0) {
if((exponent&0x1)==1)
result*=base;
exponent>>=1;
base*=base; //指數右移一位,則底數翻倍
//舉例:10^1101 = 10^0001*10^0100*10^1000
//即10^1+10^4+10^8
}
return result;
}
收獲
這道題雖然簡單,但很有價值,收獲如下:
1.double類型好像是不能直接用等號判斷,因為存在誤差(這里暫時用==好像沒問題,不確定)
2.完全掌握快速做乘方的訣竅:涉及到求解某數的n次方問題時,可以采用遞歸來完成,即利用以下公式:

3.使用右移運算符>>代替除以2,有較高的效率:exponent >> 1
4.使用位與運算符代替求余運算符%判斷奇偶數,有較高的效率:if ((exponent & 0x1) == 1)
(第三第四條以后在除以2時和判斷奇偶時一定要下意識就能想到)
5.不要忽略底數為0而指數為負的情況。
6.非遞歸實現乘方,其本質是根據指數與2的倍數關系來對底數進行操作。
7.if ((exponent & 0x1) == 1) 里面的小括號一定不能忘記!
