题目:实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
思路:
本题主要考察的是需要考虑的情况比较多:
- 指数为负数,底数为0,无意义(在Java中可以选择抛出异常)
- 指数为0,返回1
- 指数为正数(base,exponent)
- 指数为负数,底数不为0(1/base,exponent)
由于0的0次方在数学上没有意义的,因此无论是输出0还是1都是可以接收的,但这都需要和面试官说清楚,表明我们已经考虑到了这个边界值了。(正常来说不会这么输入)
测试用例:
把底数和指数分别设置为负数、0、正数。
/*
*需要考虑的情况:
*1)指数为负数,底数为0,无意义
*2)指数为0,返回1
*3)指数为正数(base,exponent)
*4)指数为负数,底数不为0(1/base,exponent)
*/
public class test_sixteen {
public double Power(double base, int exponent) throws Exception{
double res = 0.0;
if(exponent<0 && equal(base, 0)){
throw new Exception("0的负次幂无意义");
}
if (equal(base,0)) {
return 0;
}
if (exponent == 0) {
return 1.0;
}
if (exponent > 0) {
res = mutiply(base,exponent);
}else {
res = mutiply(1/base,-exponent);
}
return res;
}
public double mutiply(double base, int exponent){
double sum = 1;
for (int i = 0; i < exponent; i++) {
sum = sum * base;
}
return sum;
}
//比较两个小数,计算机会有偏差
private boolean equal(double num1, double num2) {
if((num1-num2)>-0.0000001 && (num1-num2)<0.0000001){
return true;
}else{
return false;
}
}
}
由于计算机表示小数(包括float和double型小数)都会有误差,我们不能直接用等号(==)判断两个小数是否相等。如果两个小数的差的绝对值很小,比如小于0.0000001,就可以认为他们相等。
上述的 mutiply 函数可以利用以下数学公式进一步做优化:
如果输入的指数exponent为32,我们在函数powerWithExponent的循环中需要做31次乘方。但我们可以换一种思路考虑:我们的目标是求出一个数字的32次方,如果我们已经知道了它的16次方,那么只要16次放的基础上再平方一次就可以了。而16次方又是8次方的平方。这样以此类推,我们求32次方只需要5次乘方:先求平方,在平方的基础上求4次方,在4次方的基础上求8次方,在8次方的基础上求16次方,最后在16此方的基础上求32次方。
/*
*mutiply函数可以做最佳优化
* public double mutiply(double base, int exponent){
if(exponent == 0){
return 1;
}
if(exponent == 1){
return base;
}
double result = mutiply(base, exponent >> 1); //用右移运算代替了除以2
result*=result;
if((exponent & 0x1) == 1){ //用位与运算符代替了求余运算符(%)来判断一个数是奇数还是偶数,如果是奇数还需要再乘一个base
result*=base;
}
return result;
}
*/