题目:实现函数double Power(double base,int exponent),求base的exponent次方。不得使用库函数,同时不须要考虑大数问题java
一、自觉得很简单的解法:面试
因为不须要考虑大数问题,这道题看起来很简单,可能很多应聘者在看到题目30秒后就能写出以下的代码:app
[java] view plain copy函数
不错遗憾的是,写的快不必定就能获得面试官的青睐,由于面试官会问输入的指数(exponent)小于1即 是0和负数的时候怎么办?上面的代码彻底没有考虑,只包括了指数为正数的状况。优化
二、全面但不够高效的解法,咱们离Offer已经不远了spa
咱们知道当指数为负数的时候,能够先对指数求绝对值,而后算出次方的 结果以后再取倒数。既然有求倒数,咱们很天然的就要想到有没有可能对0求倒数,若是对0求倒数怎么办?当底数base是零且指数是负数的时候,咱们不作特 殊的处理,就会发现对0求倒数从而致使程序运行出错。怎么告诉函数的调用者出现了这种错误?在Java中能够抛出异常来解决。.net
最后须要指出的是,因为0的0次方在数学上没有意义的,所以不管是输出0仍是1都是能够接收的,但这都须要和面试官说清楚,代表咱们已经考虑到了这个边界值了。blog
有了这些相对而言已经全面不少的考虑,咱们就能够把最初的代码修改以下:递归
package cglib;ip
public class List1
{
public static double power(double base,int exponent) throws Exception{
double result = 0.0;
if(equal(base,0.0) && exponent<0){
throw new Exception("0的负数次幂无心义");
}
if(equal(exponent,0)){
return 1.0;
}
if(exponent <0){
result= powerWithExponent(1.0/base, -exponent);
}
else{
result = powerWithExponent(base,exponent);
}
return result;
}
private static double powerWithExponent(double base,int exponent){
double result = 1.0;
for(int i = 1;i<= exponent;i++){
result = result*base;
}
return result;
}
//判断两个double型数据,计算机有偏差
private static boolean equal(double num1,double num2){
if((num1-num2>-0.0000001) && (num1-num2<0.0000001)){
return true;
}else{
return false;
}
}
public static void main(String[] args) throws Exception{
System.out.println(power(3, -1));
}
}
因为计算机表示小数(包括float和double型小数)都会有偏差,咱们不能直接用等号(==)判断两个小数是否相等。若是两个小数的差的绝对值很小,好比小于0.0000001,就能够认为他们相等。
此时咱们考虑得已经很周详了,已经可以获得不少面试官的要求了。可是若是咱们碰到的面试官是一个在效率上追求完美的人,那么他有可能提醒咱们函数PowerWithExponent还有更快的办法。
三、全面而高效的解法,确保咱们能拿到Offer
若是输入的指数exponent为32,咱们在函数 powerWithExponent的循环中须要作31次乘方。但咱们能够换一种思路考虑:咱们的目标是求出一个数字的32次方,若是咱们已经知道了它的 16次方,那么只要16次放的基础上再平方一次就能够了。而16次方又是8次方的平方。这样以此类推,咱们求32次方只须要5次乘方:先求平方,在平方的 基础上求4次方,在4次方的基础上求8次方,在8次方的基础上求16次方,最后在16此方的基础上求32次方。
也就是说咱们能够利用下面这个公示求a的n次方:
这个公式就是咱们前面利用O(logn)时间求斐波那契数列时,讨论的公式,这个公式很容易就能用递归实现。新的PowerWithExponent代码以下:
最后再提醒一个细节:咱们用右移运算代替除2,用位与运算符代替了求余运算符(%)来判断一个数是奇数仍是偶数。位运算的效率比乘除法及求余运算的效率要高不少。既然要优化代码,咱们就把优化作到极致。
最终代码:
package cglib;
public class List1
{
public static double power(double base,int exponent) throws Exception{
double result = 0.0;
if(equal(base,0.0) && exponent<0){
throw new Exception("0的负数次幂无心义");
}
if(equal(exponent,0)){
return 1.0;
}
if(exponent <0){
result= powerWithExponent(1.0/base, -exponent);
}
else{
result = powerWithExponent(base,exponent);
}
return result;
}
private static double powerWithExponent(double base,int exponent){
if(exponent == 0)
return 1;
if(exponent == 1)
return base;
double result = powerWithExponent(base,exponent >>1);
result *= result;
if((exponent&0x1) == 1)//0000011&00000001=00000001,10&01=0
{
System.out.println("奇数次幂");
result *=base;
}
return result;
}
//判断两个double型数据,计算机有偏差
private static boolean equal(double num1,double num2){
if((num1-num2>-0.0000001) && (num1-num2<0.0000001)){
return true;
}else{
return false;
}
}
public static void main(String[] args) throws Exception{
System.out.println(power(3, -5));
}
}
输出:
奇数次幂 0.004115226337448559