博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
剑指offer-3-面试题11:数值的整数次方(对错误的处理)
阅读量:3564 次
发布时间:2019-05-20

本文共 2916 字,大约阅读时间需要 9 分钟。

题目

实现函数 double Power( double base, int exponent ),求base 的 exponent 次方。不得使用库函数,同时不需要考虑大数问题。

本题要求实现类似于pow的功能。要求实现特定库函数(特别是处理数值和字符串的函数)的功能,是一类常见的面试题。

分析

自以为题目简单的解法

由于不需要考虑大数问题,这道题 看起来很简单,可能不少应聘者在看到题目30s后就能写出如下的代码:

double Power( double base, it exponent ){    double result = 1.0;    for( int i = 1; i<= exponent; ++i; )        result *= base;    return result;}

不过遗憾的是,写得快不一定得到面试官的青睐,因为面试官会问要是输入的指数( exponent) 小于 1 即是零和负数的时候怎么办?上面的代码完全没有考虑,只包括了指数是正数的情况。

全面但不够高效的解法

当指数为负数的时候,可以先对指数求绝对值,然后算出次方的结果之后再取倒数。既然有求倒数,我们很自然就要想到有没有可能对0求倒数,如果对0求倒数怎么办?当底数(base)是零且指数是负数的时候,如果不做特殊处理,就会出现对0求倒数从而导致程序运行出错。怎么告诉函数的调用者出现这种错误?前面提到可以采用3种方法:返回值、全局代码和异常。面试的时候可以向面试官阐述每种方法的优缺点,然后一起讨论决定选用哪种方式。

最后需要指出的是,由于0的0次方在数学上是没有意义的,因此无论是输出0还是1都是可以接受的,但这都需要和面试官说清楚,表明我们已经考虑到这个边界值了。

bool g_InvalidInput = false;double Power( double base, int exponent ){    g_InvalidInput = false;    if( equal( base, 0.0 )&& exponent < 0 )    {        g_InvalidInput = true;        return 0.0;    }    unsigned int absExponent = ( unsigned int ) ( exponent );    if( exponent < 0 )         absExponent = ( unsigned int )( -exponent );    double result = PowerWithUnsignedExponent( base, absExponent );    if( exponent < 0 )        result = 1.0 / result;    return result;} double PowerWithUnsignedExponent( double base, unsigned int exponent ){    double result = 1.0;    for( int i = 1; i<= exponent; ++i )        result *= base;    return result;}bool equal( double num1, double num2 ){    if( (num1-num2 > -0.0000001) && (num1-num2 < 0.0000001 ))        return true;    else         return false;}

上述代码中我们采用的是全局变量来标识是否出错。如果出错了,则返回的值是0.但为了区分是出错的时候返回的0,还是底数为0的时候正常运行返回的0,我们还定义了一个全局变量 g_InvalidInput。当出错时,这个变量被设为true,否则为false。这样做的好处是,可以把返回值直接传递给其他变量,比如写 double result = Power( 2,3 )。也可以把函数的返回值直接传递给其他需要double 型参数的函数。但缺点是这个函数的调用者有可能会忘记检查g_InvalidInput以判断是否出错,留下了安全隐患。由于有优点也有缺点,因此在写代码之前要和面试官讨论采用哪种出错处理方式最合适。

一个细节值得我们注意:在判断底数base是不是等于0时,不能直接写 base == 0,这是因为在计算机内表示小数时(包括float 和 double型小数)都有误差。判断两个小数是否相等,只能判断它们之差的绝对值是不是在一个很小的范围内。如果两个数相差很小,就可以认为它们相等。这就是我们定义函数equal的原因。

看代码可以看出 PowerWithUnsignedExponent 还有更快的办法。

全面又高效的解法

如果输入的指数 exponent 为 32,我们在函数PowerWithUnsignedExponent的循环中需要做31次乘法。但是可以换一种思路考虑:我们的目标是求出一个数字的32次方,如果我们已经知道了它的16次方,那么只要在16次方的基础上再平方一次就可以了。而16次方是8次方的平方。这样以此类推,我们求32次方只需要做5次乘法:先求平方,在平方的基础上求4次方,在4次方的基础上求8次方,在8次方的基础上求16次方,最后在16次方的基础上求32次方。

这里写图片描述

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

最后提醒一个细节:用右移运算符代替了除以2,用位与运算符代替了求余运算符(%)来判断一个数是奇数还是偶数。位运算的效率比乘除法及求余运算的效率要高很多。既然要优化代码,我们就把优化做到极致。

在面试的时候,我们可以主动提醒面试官注意代码中的两处细节(判断base是否等于0和用位运算替代乘除法及求余运算),让他知道我们对编程的细节很重视。细节很重要,因为,细节决定成败。

测试用例&代码

把底数和指数分别设为正数、负数和零

本题考点

(1)思维的全面性。这个问题本身不难,但是能顺利通过的应聘者不是很多。有很多人会忽视底数为0而指数为负数时的错误处理

(2)对效率要求比较高的面试官还会考查应聘者快速做乘方的能力。

你可能感兴趣的文章
可调谐半导体激光器的窄线宽测试及压缩
查看>>
matlab中 %d,%f,%c,%s
查看>>
常见的光纤接头汇总
查看>>
半导体激光器—问题整理(二)
查看>>
科研日记7.31
查看>>
zemax仿真二向色镜
查看>>
stm32单片机编程时extern的用法
查看>>
UART4和5的问题
查看>>
Spring框架中在并发访问时的线程安全性
查看>>
网站部署
查看>>
什么情况下会发生栈内存溢出。
查看>>
何为去中心化
查看>>
缓存一致性:写策略
查看>>
Cache一致性:MESI
查看>>
缓存一致性:写未命中
查看>>
为什么用中间位作为组索引
查看>>
缓存:局部性
查看>>
mysql原理:b+树索引
查看>>
mysql原理:最左原则
查看>>
mysql原理:join标到底是什么,为什么有军规不建议超过三个
查看>>