更多剑指offer面试习题请点击: 《剑指offer》(第二版)题集目录索引
题目:
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
解题思路:
很多人可能一开始看到不需要考虑大数问题,就觉着这题很简单,快速的写下下面的代码:
< code >
double power(double base, int exponent)
{
double result = 1.0;
int i = 0;
for (i = 0; i <= exponent; i++)
{
result *= base;
}
return result;
}
这段代码对于底数、指数均为正数的情况下是没毛病的,但如果输入的指数小于等于零,那就会出问题了。这段代码完全没考虑到这些特殊情况。
当指数exponent为负数时,我们先对指数求绝对值abs_exponent,计算出底数的abs _exponent次方,然后对结果求倒。但当底数为0时,对0求倒就会出现错误,这个时候就要把错误告诉函数调用者,一般可以使用以下三种方法。
项目 | 优 点 | 缺点 |
---|---|---|
返回值 | 和系统API一致 | 不能方便的使用计算结果 |
全局变量 | 能够方便的使用计算结果 | 用户可能会忘记检查全局变量 |
异常 | 可以为不同的出错原因定义不同的异常类型,逻辑清晰明了 | 有些语言不支持异常,抛出异常时对性能有负面影响 |
这里我们采用第二种方法:全局变量。设置一个int型全局变量invalid_input,初始值是0,当出错时置为1,这样可以很方便的显示出错的情况。写到这可能大家觉的这个函数差不多了,边界值啥的都考虑到了,但我们不能忘了一个最重要的东西——效率。
注意: pow函数和我们平常理解的数学有点差异。比如:
在数学里面0^0是未定式;
但在离散里面0^0=1;
在计算机中,规定了0^0=1;
解题思路:
< code >
double power_unsigned_exponent(double base, unsigned int exponent) //递归
{
if (0 == exponent)
return 1;
if (1 == exponent)
return base;
double result = 1.0;
double tmp = base;
while (exponent != 0)
{
if ((exponent & 1) == 1) // 当前指数的二进制最低位为不为1
{
result *= tmp; // 就计算一个乘积
}
tmp *= tmp; // 翻倍
exponent >>= 1; // 右移一位
}
return result;
}
解题思路:
我们要计算一个数的32次方,如果已经知道他的16次方的值了,那就只用把他的16次方的值平方一次就可以了。而16次方又是8的平方,这样一次类推,求一个数的32次方只要进行做5次乘法就够了。
先求平方,在平方的基础上求4次方,在4次方的基础上求8次方,在8次方的基础上求16次方,在16次方的基础上求32次方。
< code >
/*错误标识码,1代表输入有误,0代表输入正确*/
int invalid_input = 0;
/*判断两个double类型的数据是否相等*/
int equal(double number1, double number2)
{
if ((number1 - number2 < 0.0000001) && (number1 - number2 > -0.0000001))
return 1;
else
return 0;
}
double power_unsigned_exponent(double base, unsigned int exponent) //递归
{
if (0 == exponent)
return 1;
if (1 == exponent)
return base;
double result = power_unsigned_exponent(base, exponent >> 1);
result *= result;
/*用 >> 代替除2,用&代替判断奇数%2,提高效率*/
if (exponent & 1)
result *= base;
return result;
}
double power(double base, int exponent)
{
double result = 0.0;
unsigned int abs_exponent = (unsigned int)exponent;
/*底数为0且指数为负数情况下,直接返回0.0,但此时invalid_input置为1,代表输入的数据有误*/
if (equal(0.0, base) && exponent < 0)
{
invalid_input = 1;
return 0.0;
}
/*先把负指数转换成正的*/
if (exponent < 0)
abs_exponent = (unsigned int)(-exponent);
result = power_unsigned_exponent(base, abs_exponent);
/*指数为负,对最后结果求倒*/
if (exponent < 0)
result = 1.0 / result;
return result;
}
//==========================测试代码===============================
void test(char* testName, double base, int exponent, double expected_result, int expected_flag)
{
double result = power(base, exponent);
if (equal(result, expected_result) && invalid_input == expected_flag)
printf("%s passed\n", testName);
else
printf("%s FAILED\n", testName);
}
int main()
{
/*底数、指数均为正数*/
test("test1", 3, 3, 27, 0);
/*底数为负数,指数为正数*/
test("test2", -2, 2, 4, 0);
/*底数为正数,指数为负数*/
test("test3", 2, -2, 0.25, 0);
/*底数为正数,指数为0*/
test("test4", 2, 0, 1, 0);
/*底数、指数均为0*/
test("test5", 0, 0, 1, 0);
/*底数为0,指数为正数*/
test("test6", 0, 2, 0, 0);
/*底数为0,指数为负数*/
test("test7", 0, -2, 0, 1);
system("pause");
return 0;
}