剑指offer—数值的整数次方

面试题11:题目:实现函数double power(double base , int exponment) ,求base的exponment次方。不得使用库函数,同时不需要考虑大数问题。

我想刚看到这个问题,很可能好多人都笑了,觉得是很简单的一道题,接下来就拿起笔来直接写了。
例如实现1:

#include<stdio.h>
#include<stdlib.h>
double Power(double base, int exponent)
{
    double ret = 1;

        while (exponent)
        {
            ret *= base;
            exponent--;
        }

    return ret;
}
int main()
{
    double base = 0;
    int exponent = 0;
    double ret = 0;
    printf("please enter a base number:");
    scanf("%lf", &base);
    printf("please enter a exponent number:");
    scanf("%d", &exponent);
    ret = Power(base, exponent);
    printf("%lf", ret);
    system("pause");
    return 0;
}

这种办法是你最先开始就能想到的,但是我想如果你把这一种方法递给面试官,面试官肯定不会满意的。面试官这个时候会说如果输入的指数小于1的时候怎么办?即是0和负数的情况。上面的代码只解决了大于0的情况。

所以接下来我们就来解决为0或者为负数的情况。

#include<stdio.h>
#include<stdlib.h>
double Power(double base, int exponent)
{
    double ret = 1;
    if (exponent > 0)
    {
        while (exponent)
        {
            ret *= base;
            exponent--;
        }
    }
    else if (exponent < 0)
    {
        exponent = (unsigned int)(-exponent);
        while (exponent)
        {
            ret *= base;
            exponent--;
        }
        ret = 1.0/ret;
    }
    else
        ret = 1;
    return ret;
}
int main()
{
    double base = 0;
    int exponent = 0;
    double ret = 0;
    printf("please enter a base number:");
    scanf("%lf", &base);
    printf("please enter a exponent number:");
    scanf("%d", &exponent);
    ret = Power(base, exponent);
    printf("%lf", ret);
    system("pause");
    return 0;
}

这样我们就解决了指数的边界情况。

这时候我们解决了指数,当然要考虑一下底数,当底数为0时你怎么解决呢?当底数是零并且指数是负数怎么解决呢?如果我们不对此做特殊处理,就会出现当0做分母时出现问题。在这里,我们当然要把这种错误返回给用户,在这里,我们可以采用返回值,全局代码和异常。面试的时候我们就可以向面试官阐述各种的优缺点,然后讨论选定用哪一种。

#include<stdio.h>
#include<stdlib.h>
#define EPSINON 0.0000000001
double Power(double base, int exponent)
{
    double ret = 1;
    if (((base -0.0)>-EPSINON)&&(base-0.0)<EPSINON)
    {
        if (exponent >= 0)
        {
            ret = 0.0;
            return ret;
        }
        else
            return -1; //这里对于错误清况,我们返回-1。
    }
    if (exponent > 0)
    {
        while (exponent)
        {
            ret *= base;
            exponent--;
        }
    }
    else if (exponent < 0)
    {
        exponent = (unsigned int)(-exponent);
        while (exponent)
        {
            ret *= base;
            exponent--;
        }
        ret = 1.0 / ret;
    }
    else
        ret = 1;
    return ret;
}
int main()
{
    double base = 0;
    int exponent = 0;
    double ret = 0;
    printf("please enter a base number:");
    scanf("%lf", &base);
    printf("please enter a exponent number:");
    scanf("%d", &exponent);
    ret = Power(base, exponent);
    printf("%lf", ret);
    system("pause");
    return 0;
}

这里我们要清楚,在这里对double类型的数据和0进行比较时,这时就有一个浮点型类型比较的问题,要定义精度。在这里我们只能判断两个浮点数的差的绝对值是不是再一个很小的范围内。如果两个数相差很小,就可以认为它们相等。

上述过程我们已经考虑的很周详了,但是如果当有一个追求完美效率的面试官,那么他会给我们一种更快的办法。在这里我们需要快速做乘方。

#include<stdlib.h>
#include<stdio.h>
#define EPSINON 0.0000000001

double PowerWithUnsignedExponent(double base, int exponent)
{
    if (exponent == 0)
        return 0;
    if (exponent == 1)
        return base;
    double result = PowerWithUnsignedExponent(base, (exponent >> 1));
    result *= result;
    if ((exponent & 0x1) == 1)
    {
        result *= base;
    }

    return result;
}
double Power(double base, int exponent)
{
    double ret = 1;
    if (((base - 0.0)>-EPSINON) && (base - 0.0)<EPSINON)
    {
        if (exponent >= 0)
        {
            ret = 0.0;
            return ret;
        }
        else
            return -1;
    }
    unsigned int absexponent = (unsigned int)(exponent);
    if (exponent < 0)
    {
        absexponent = (unsigned int)(-exponent);
    }
    ret = PowerWithUnsignedExponent(base, absexponent);
    if (exponent < 0)
    {
        ret = 1.0 / ret;
    }

    return ret;
}

int main()
{
    double base = 0;
    int exponent = 0;
    double ret = 0;
    printf("please enter a base number:");
    scanf("%lf", &base);
    printf("please enter a exponent number:");
    scanf("%d", &exponent);
    ret = Power(base, exponent);
    printf("%lf", ret);
    system("pause");
    return 0;
}

在这里,如当我们输入exponent为32,在在最初那种循环我们需要进行31次乘法运算才行,这样就会让效率低一些。我们可以换一种思路,当我们求32次方时,求得16次方,然后平方一次就可以了,然后16又是8次方再给平方,就这样依次进行下去,我们就可以32次方,只需要5次就可以解决了!是不是效率很高呢。所以我们最后利用递归完成了这一次的优化,在这里对次方除2我们用移位运算来做,然后对指数判断是奇数还是偶数。大家要记得,位运算的运算效率比乘除法的效率要高,所以记得以后碰到乘除法的问题,我们可以考虑用位运算做。

你可能感兴趣的:(剑指offer—数值的整数次方)