数值的整数次方(优秀的代码就是要注意很多的细节)
通常越是看似简单的题目(因为没有大数问题),其实真正写代码的时候就会忘记很多的细节
比如此题大多数童鞋估计看到后就会立刻写出如下代码
double powerWithUnsignedExponent(double base, int exponent){
double result = 1.0;
for(int i = 0; i <= exponent; ++i){
result *= base;
}
return result;
}
可是如果你写出上面的代码立刻就交给了面试官,那也意味着你与offer已经无缘了
当然前提你需要写出逻辑正确的代码,然后才是优化性能
需要注意的几个点:1、如果幂exponent为负数呢 2、底数如果是 0 && 幂为负数呢 3、如果输入非法怎么告知调用函数者 4、能不能更高效
其中有个容易遗忘的知识点 double a; 不能用 a == 0 来判断a是否为0 因为对于double类型来说 0 不是绝对精确的结果; 所以应该用类似 abs(a - 0.0 ) < 0.000001 来判断
第一点:如果幂exponent为负数 首先计算出幂为整数的值 然后取倒数即可;
第二、三点:对于输入非法的情况,我们有三种解决办法 a、异常(高级语言推荐)优点:可以为不同的出错原因定义不同异常类型 逻辑清晰 缺点:抛出异常对性能有些许负面影响 b、设置一个全局变量标志来指示输入非法与否;优点:能方便的使用计算结果,缺点:调用者容易忘记判断标志符; c、用返回值,优点:和系统API一致 缺点:不能方便的使用计算结果
第四点:把exponent 拆开计算 分奇数与偶数两种情况 (基本的数学原理)
public static double power(double base, int exponent) throws Exception{
//如果底为0 幂为负数 则为非法输入
if( Math.abs(base-0.0) < 0.0000001 && exponent < 0 ){
throw new Exception("您输入的底数与幂有错误,请检查");
}
if( 1.0 == base ){
return 1.0;
}
int absExponent = Math.abs(exponent); //absExponent 为exponent取正值
double result = powerWithUnsignedExponent(base,absExponent); //调用幂为正的合法计算结果
if(exponent < 0){ //如果幂为负值,则把幂为正的计算结果取倒数即可
result = 1.0/result;
}
return result;
}
//计算输入合法且 幂为正的结果
private static double powerWithUnsignedExponent2(double base, int exponent){
double result = 1.0;
for(int i = 0; i <= exponent; ++i){
result *= base;
}
return result;
}
上述代码不一定会让面试官十分满意,因为还可以更高效,函数double powerWithUnsignedExponent(double base, int exponent) 可以改为如下高效的算法
public static double powerWithUnsignedExponent(double base, int exponent){
if( 0 == exponent ){
return 1.0;
}
if( 1 == exponent){
return base;
}
double result = powerWithUnsignedExponent(base, exponent >> 1);
result *= result;
if( 1 == (exponent & 0x1))
result *= base;
return result;
}
上述代码中 exponent >> 1 代替了除以2 位与运算代替了求余(%)运算 因为位运算要比乘除法运算要高效很多,既然优化性能就要优化到极致
但是上述代码虽然得到了性能优化,但是有一定的风险,因为用到了递归;就要考虑 栈 的问题,如果递归过深 有 栈溢出的风险,这个就要和面试官沟通了