第16题:数值的整数次方
题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
代码的完整性:
1.功能测试
2.边界测试
3.负面测试
3种处理方法/优点/缺点
1.返回值/与系统API一致/无法直接作为函数参数
2.全局变量/可以直接作参数/可能忘记检查,有安全隐患
3.抛出异常/逻辑明了/有些语言不支持异常
思路
//1.全局变量标记异常值
bool g_InvalidInput = false;
//大函数
//2.初始化全局变量
//3.如果输入底数为0,指数为负,返回0,且异常
//4.设置无符号变量存放指数的绝对值
//5.调用求指数的函数,设置double型储存指数的结果
//6.如果指数是负数,就求倒数
//7.返回结果
//求指数的函数double,参数:底数double,指数unsigned int,返回值:结果double。这里的指数已经取了绝对值,所以是unsigned int。
//1.如果指数为0,返回1
//2.如果指数为1,返回底数
//由于数学知识可知,
//如果exponent为偶数,result=base^(exponent/2)*base^(exponent/2)
//如果exponent为偶数,result=base^((exponent-1)/2)*base^((exponent-1)/2)*base
//3.使用递归,可以得到base^(exponent/2),即div2的结果,用右移一位,>>1会更快
//4.将上面递归函数得到的div2的结果相乘
//5.判断原来的指数的奇偶性,如果是奇数,就再乘以一个底数。这里用与位运算更快。
//6.返回结果
我的:运行时间: 4 ms 占用内存:376K
double PowerWithUnsignedExponent(double base, unsigned int exponent);
//1.全局变量标记异常值
bool g_InvalidInput = false;
double Power(double base, int exponent) {
//2.初始化全局变量
g_InvalidInput = false;
//3.如果输入底数为0,指数为负,返回0,且异常
if (base == 0.0 && exponent<0)
{
g_InvalidInput = true;
return 0;
}
//4.设置无符号变量存放指数的绝对值
unsigned int absExponent = (unsigned int)exponent;
if (exponent<0)
{
absExponent = -exponent;
}
//5.调用求指数的函数,设置double型储存指数的结果
double result = PowerWithUnsignedExponent(base, absExponent);
//6.如果指数是负数,就求导
if (exponent<0)
result = 1 / result;
//7.返回结果
return result;
}
//求指数的函数double,参数:底数double,指数unsigned int,返回值:结果double。这里的指数已经取了绝对值,所以是unsigned int。
double PowerWithUnsignedExponent(double base,unsigned int exponent)
{
//1.如果指数为0,返回1
if (exponent == 0)
return 1;
//2.如果指数为1,返回底数
if (exponent == 1)
return base;
//由于数学知识可知,
//如果exponent为偶数,result=base^(exponent/2)*base^(exponent/2)
//如果exponent为偶数,result=base^((exponent-1)/2)*base^((exponent-1)/2)*base
//3.使用递归,可以得到base^(exponent/2),即div2的结果,用右移一位,>>1会更快
double result = PowerWithUnsignedExponent(base, exponent >> 1);
//4.将上面递归函数得到的div2的结果相乘
result = result*result;
//5.判断原来的指数的奇偶性,如果是奇数,就再乘以一个底数。这里用与位运算更快。
if (exponent & 1)
result *= base;
//6.返回结果
return result;
}
优化 运行时间: 4 ms 占用内存:468K
class Solution {
public:
double Power(double base, int exponent) {
if(exponent>0)
{
if(exponent==1)
return base;
if(!exponent&1)//为偶数
return Power(base,exponent/2)*Power(base,exponent/2);
else
return Power(base,exponent/2)*Power(base,exponent/2+1);
}
else if (exponent==0)
{
return 1;
}
else
{
return 1/Power(base,0-exponent);
}
}
};
不用递归 简单快速幂 运行时间: 3 ms 占用内存:484K
涉及到二分法的思想。 p的二进制位,如果某位等于1,就乘以base^该位置
class Solution {
public:
double Power(double base, int exponent) {
long long p = abs((long long)exponent);
double r = 1.0;
while(p){//用循环,不用递归。
if(p & 1) r *= base;//奇数。上一层的结果乘以底数。
base *= base;//上一层的结果相乘。
p >>= 1;//进入下一层。
}
return exponent < 0 ? 1/ r : r;
}
};
base = 0.0 ,exponent < 0 时 ,1/r = 1/0 报错...这个异常不应该在这个层次上处理,而是在调用的层次上...
其它解法
/**
* 1.全面考察指数的正负、底数是否为零等情况。
* 2.写出指数的二进制表达,例如13表达为二进制1101。
* 3.举例:10^1101 = 10^0001*10^0100*10^1000。
* 4.通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果。
*/
public double Power(double base, int n) {
double res = 1,curr = base;
int exponent;
if(n>0){
exponent = n;
}else if(n<0){
if(base==0)
throw new RuntimeException("分母不能为0");
exponent = -n;
}else{// n==0
return 1;// 0的0次方
}
while(exponent){
if(exponent&1)//奇数
res*=curr;
curr*=curr;// 翻倍
exponent>>=1;// 右移一位
}
return n>=0?res:(1/res);
}