剑指offer——实现函数double Power(double base,int exponent),求base的exponent次方,不得使用库函数,同时不需要考虑大数问题。
自以为题目简单的解法:用for或者while循环
double Poweruint(double a, unsigned int ex)
{
double ret = 1.0;
while (ex--){
ret *= a;
}
return ret;
}
可是这个程序只包括了指数是正数的情况,指数是负数和零的时候怎么办?我们都知道,
- 任何非零数的零次方为1,0的0次方没有意义,因此输出0或1都是可以接受的。
- 指数为负数时,先对指数求绝对值,然后算出次方的结果再求倒数。
- 底数为0,指数为负数时,要对0求倒数会导致程序运行出错,因此要做特殊处理,可以采用三种方法:返回值,全局代码和异常。 这个题的解法中我们采用了全局变量来标识是否出错,如果出错则返回0值。为了区分返回的0值是输出结果还是出错处理,再定义一个变量flag,初始化为0,如果是出错导致结果输出为0则令flag=1来标识。
- 计算机表示小数都有误差,我们不能直接用等号(==)判断,要使两个数的差值在一个精度内。
在考虑了指数的各种情况后,我们可以考虑优化次方函数,如输入的指数为32,在for循环中需要做31次乘法。但我们可以换一种思路:
目标次数是32,如果知道了它的16次方,那么在16次方基础上平方就可以了。而16次方是8次方的平方,以此类推,求32次方只需要做5次乘法:先求平方,再平方基础上求4次方,4次方基础上求8次方,8次方基础上求16次方,16次方,基础上求32次方。
可以用下面的公式求解:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int equal(double a, double b)//比较两个浮点数是否相等
{
if ((a - b) > -0.000001 && (a - b) < 0.000001){
return 1;
}
else{
return 0;
}
}
double Poweruint1(double a, unsigned int ex)//低效率
{
double ret = 1.0;
//for (unsigned int i = 0; i <= ex; i++){
// ret *= a;
//}
while (ex--){
ret *= a;
}
return ret;
}
double Poweruint2(double a, unsigned int n)//位运算效率比乘除法和求余运算高
{
if (0 == n){
return 1.0;
}
if (1 == n){
return a;
}
double ret = Poweruint2(a, n >> 1);
//double ret = Poweruint2(a, n/2);
ret *= ret;
if (1 == (n & 1)){
ret *= a;
}
//if (1 == (n % 2)){
// ret *= a;
//}
return ret;
}
double Power(double base, int exponent)
{
int flag = 0;
double result = 1.0;
unsigned int ex = (unsigned int)exponent;
if (equal(base, 0.0) && exponent < 0){//底数为0并且指数小于0
flag = 1;
return 0.0;
}
if (exponent < 0){//指数为负数时先转化为正数
ex = (unsigned int)(-exponent);
}
/*result = Poweruint1(base, ex);*/
result = Poweruint2(base, ex);
if (exponent < 0){
result = 1.0 / result;
}
return result;
}
int main()
{
double result = Power(0,0);
printf("%f\n", result);
system("pause");
return 0;
}