第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);       
}

 

posted @ 2019-02-03 00:01 lightmare 阅读(...) 评论(...) 编辑 收藏