题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
题目分析
这道题目看似简单,很多人都可以在30秒就写出传统的代码,如下:
public double powerWithExponent(double base,int exponent){
double result = 1.0;
for(int i = 1;i<= exponent;i++){
result = result*base;
}
return result;
}
但是,这个代码并没有考虑到输入的指数小于1即为0或者负数的情况。当我们知道指数为负数的时候,可以先求指数的绝对值,然后算出次方的结果之后再取倒数。既然需要求倒数,那么自然就要想到对0求倒数如何处理,在Java中我们可以用抛出异常的方法来处理。同时还需要指出,由于0的0次方在数学上是没有意义的,所以无论输出0还是1都可以接受,但是需要跟面试官说清楚。还有一个需要注意的点,判断double类型的底数是否为0,不能直接用base==0判断,因为计算机内表示小数(double和float)的时候都有误差,判断两个小数是否相等,只能判断它们的差的绝对值是否在一个很小的范围内,如果是,则可以认为二者相等。
在效率上继续考虑优化,若用上述传统的累乘的方法求次方,当exponent很大的时候,需要循环做很多次乘法,这是很低效的,
因此我们可以用如下公式求a的n次方:
通过这个公式,就可以递归的实现求a的n次方了,减少乘法的循环次数。既然要优化代码,那我们就优化的极致:我们知道位运算相比乘、除、求模运算效率更高,所以在方法内部,我们用右移一位来代替“除以2”,用与1按位与运算来代替求模运算进而判断指数是否为奇数。
public class Power {
public double power(double base, int exponent) throws Exception {
double result = 0.0;
//底数为0,且指数为负数
if((equal(base,0.0)) && (exponent < 0)){
throw new Exception("0的负数次幂无意义");
}
//指数为0
if(exponent == 0)
return 1;
//指数为负数
if(exponent < 0)
result = powerWithExponent(1.0/base, -exponent);
//指数为正数
if(exponent>0)
result = powerWithExponent(base,exponent);
return result;
}
//用累乘计算次方,这种方法效率不高
public double powerWithExponent(double base, int exponent){
double result = 1.0;
for(int i = 1; i <= exponent; i++)
result = result * base;
return result;
}
//用a^n=a^(n/2)*a^(n/2)或者a^((n-1)/2)*a^((n-1)/2)*a递归原理,减少乘法的次数
//用移位运算代替*/%运算,提高效率:右移一位相当于除以2,左移一位相当于乘以2,x与1按位与如果结果为1则x为奇数
public double powerWithExponent1(double base,int exponent){
if(exponent == 0)
return 1;
if(exponent == 1)
return base;
double result = powerWithExponent(base, exponent >> 1);
result *= result;
//判断exponent是否为奇数,如果为奇数还需要再乘一遍base
if((exponent & 0x1)==1)
result = result*base;
return result;
}
//计算机表示小数(float和double)都有误差,不能直接用==判断两个小数是否相等。
//如果两个小数的绝对值很小,比如小于0.0000001,就可以认为它们相等。
public boolean equal(double num1,double num2){
if(((num1-num2)>-0.000000001)&&((num1-num2)<0.000000001))
return true;
else
return false;
}
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Power p = new Power();
System.out.println(p.power(2, -3));
}
}