剑指Offer——数值的整数次幂
题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0。
解法一:直接法
注意的问题:
1、 关于次幂的问题特殊的情况,比如次幂为负数,或者基数为0时等等复杂的情况。(由于指数是int 类型,所以要区分整数还是负数或者0.)
2 、机器中浮点数的比较是由误差的,因此double类型的比较,不能用简单的a==0来比较。一般的比较方式是,相减的差在一个很小的区间内,我们就认为是相等的。
直接方法:直接连续累乘。
public class Solution {
public double Power(double base, int exponent) {
double mul=1.0;
/* 如果exponent = 0 输出1 */
if(exponent == 0)
{
return 1.00000;
}
/* 如果base = 0 输出0 */
if(base >= -0.000001 && base <= 0.000001)
{
return 0;
}
/* 如果指数大于0 */
if(exponent > 0)
{
for(int index = 0; index < exponent; index++)
{
mul *= base;
}
}
else
{
exponent = -exponent;
for(int index = 0; index < exponent; index++)
{
mul *= base;
}
mul = 1.0/mul;
}
return mul;
}
}
解法二:快速幂运算
分析:直接累乘的方法固然很简单,但是往往会造成多次相乘运算,这样反而不好。
将指数用二进制数表达,例如:13表达为二进制1101。 通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果。
举例:10^1101 = 10^0001 * 10^0100 * 10^1000。
仔细观看上面公式发现:
我们可以通过在循环里通过自乘运算依次实现,而 这些指数前面的系数=指数对应的每一位二进制数。exponent = 11 = 1011(二进制)。
所以,我们可以这样实现这个快速幂运算。
-
step1:首先需要知道在每次循环里通过自乘计算base的2的指数次方。循环的次数就是所求指数exponent的二进制位数
-
step2: 其次就是对于每个base的2的指数次方,乘以其相对应的二进制位上的数。
-
step3: 循环里不断的累成step2里计算的结果。
public class Solution {
public double Power(double base, int exponent) {
double result = 1.0,currentResult = base;
int n = 0;
if(exponent > 0) {
n = exponent;
} else if(exponent < 0) {
if(base == 0){
new RuntimeException("分母不能为0");
}
n = - exponent;
}else if(exponent == 0) {
//0的0次幂
return 1.0;
}
while(n != 0) {
if((n & 1) == 1){
result *= currentResult;
}
//当前结果翻倍(因为上面公式的每一个项base^2会加倍)
currentResult *= currentResult;
//将exponent指数的二进制形式右移一位,继续循环,取出二进制的最低位
n = n >> 1;
}
if(exponent >= 0) {
return result;
}else {
return (1/result);
}
}
}
递归解决:
double Power(double base, int exponent) {
//指数为0时,结果为1
if(exponent == 0)
return 1;
//底数为0时,结果为0
if(base == 0)
return 0;
//指数为1时,结果为base
if(exponent == 1)
return base;
//指数为-1时,结果为1/base
else if(exponent == -1)
return 1/base;
//其它情况(分解幂计算)
return Power(base,exponent/2) * Power(base,exponent/2) * Power(base,exponent%2);
}