《剑指offer》:自己写一个pow函数

原创 2016年08月30日 10:58:50

缘由

今天打google在codejam上办的apactest,成绩还行吧(最后排名540),第二题逗比了,自己逻辑后来理清楚,但是代码还是原来的想法,wa了两次才找到了bug。
apactest

第二题需要实现一个整数的pow函数,之前只会递归的写法,今天学会了迭代的写法,回想《剑指offer》里也有类似的东西,所以整理成这篇博客。

整数的非负整数次幂(不考虑大数)

线性求幂

比如求2的10次幂,可能有人随手十几秒就写完了:

typedef long long LL;
LL pow(int base, int exponent) {
    LL ans = 1;
    for (int i = 0; i < exponent; ++i) {
        ans *= base;
    }
    return ans;
}

如果exponent是比较大的呢?有没有更快的?

快速幂算法登场

我们把exponent表示成二进制的形式,比如15=1111,那么其实有:

a11=a10112=a10002+102+12=a10002a102a12=a8a2a1

这样计算的话,我们只需要计算log2(exponent)次就够了!对比23232,完全不一样的数量级!

那么代码怎么写呢?

typedef long long LL;
LL pow(int base, int exponent) {
    LL ans = 1, last_pow = base;
    while (exponent > 0) {
        // 如果最低位为1
        if ((exponent & 1) != 0)
            ans = ans * last_pow ;
        exponent = exponent >> 1;
        last_pow = last_pow * last_pow;
    }
    return ans;
}

其实我觉得代码已经很清楚了,如果还不清楚的话,可以稍微解释一下(请先自行熟悉位运算):
假如我们使用上面的函数来迭代计算311,根据上面所使用的公式,11表示为二进制是1011,计算过程是这样的:
第一步:发现1011的最低位为1,ans乘上31为3,1011右移一位变成101;
第二步:发现101的最低位为1,ans乘以32变成27,101右移一位变成10;
第三步,发现10的最低位不为1,ans不变,10右移一位变成1;
第四步,发现1的最低位为1,ans乘以38变成177147,1右移一位变成0,退出while循环。

注意每一步里的31323438是怎么来的呢?用的就是last_pow(注意初始值)这个量来每次平方自己计算出来的!第三步里虽然ans不变,但是last_pow还是得平方一下,否则没法在第四步里变成所需要的38

整数次幂

注意现在的问题变成了整数次幂了,也就是包括负数次幂了!
首先回顾一下幂运算的定义:

ax=1axx

a0=1a0

也就是说,对于负数次幂,其实只要计算它的绝对值次幂,再用1去除就可以了,还要注意检查计算0的0次幂这种非法情况!

typedef double NumberType;

// 计算非负整数次幂的函数
NumberType powWithoutNegativeExp(NumberType base, int exponent) {
    NumberType ans = 1, last_pow = base;
    while (exponent > 0) {
        if ((exponent & 1) != 0)
            ans = ans * last_pow ;
        exponent = exponent >> 1;
        last_pow = last_pow * last_pow;
    }
    return ans;
}

// 浮点数相等的判断比较特别
bool equalD(NumberType numA, NumberType numB) {
    static const NumberType ERROR = 1e-12;
    return (numA - numB <= ERROR && numA - numB >= -ERROR);
}

// 处理各种情况的幂运算的函数
NumberType pow(NumberType base, int exponent) {
    // 0的0次幂没有意义,抛出异常
    if (exponent == 0 && equalD(base, 0)) {
        throw logic_error("Zero's zero exponent is undefine.");
    }

    bool isNegative = false;
    if (exponent < 0) {
        isNegative = true;
        exponent = -exponent;
    }

    NumberType result = powWithoutNegativeExp(base, exponent);
    return isNegative ? 1 / result : result;
}

注释代码里有了~应该是很清晰的。

另附上完整的使用示例:

#include <iostream>
#include <stdexcept>
using namespace std;

typedef double NumberType;

NumberType powWithoutNegativeExp(NumberType base, int exponent) {
    NumberType ans = 1, last_pow = base;
    while (exponent > 0) {
        if ((exponent & 1) != 0)
            ans = ans * last_pow ;
        exponent = exponent >> 1;
        last_pow = last_pow * last_pow;
    }
    return ans;
}

bool equalD(NumberType numA, NumberType numB) {
    static const NumberType ERROR = 1e-12;
    return (numA - numB <= ERROR && numA - numB >= -ERROR);
}

NumberType pow(NumberType base, int exponent) {
    if (exponent == 0 && equalD(base, 0)) {
        throw logic_error("Zero's zero exponent is undefine.");
    }

    bool isNegative = false;
    if (exponent < 0) {
        isNegative = true;
        exponent = -exponent;
    }

    NumberType result = powWithoutNegativeExp(base, exponent);
    return isNegative ? 1 / result : result;
}


int main() {
    for (double i = 1.1; i < 1.5; i+=0.1) {
        for (int j = 1; j < 10; ++j)
            cout << i << ' ' << j << ' ' << pow(i, j) << endl;
    }

    return 0;
}

pow(x,y)函数的用法及实现算法

pow函数是求次方的函数, 函数原型是double pow(double a,double b); 使用时应包含math.h头文件。 1,C/C++中的数学函数编辑 原型:在TC2.0...
  • changgui5211
  • changgui5211
  • 2015年07月11日 18:15
  • 7159

探索c++的函数pow()的实现方法·数学与程序设计的结合(zz)

 计算t的m次幂的方法:(探索c++的函数pow()的实现方法,数学与程序设计的结合)源程序下载:http://pjy.studio.googlepages.com/powP.cpp或到我的收藏下载。...
  • xiaoxiongli
  • xiaoxiongli
  • 2008年02月29日 19:58
  • 18329

Math.pow函数的Java实现。

  • 2014年03月24日 23:34
  • 2KB
  • 下载

C语言10的n次方pow函数不好用,自己写一个简单的

C语言中有两个函数可以实现10的n次方,分别是double pow(double x, double y),double pow10(int p) 前者是实现x的y次方,后者是实现10的p次方 使用这...
  • wyqwclsn
  • wyqwclsn
  • 2014年10月09日 14:13
  • 5463

pow()函数自实现

题目:实现函数double power(double base, int exponent),求base的exponent次方。不得使用库函数同时不需要考虑大数问题。 其实这道题就是要实现pow这个库...
  • qq_33724710
  • qq_33724710
  • 2016年05月03日 15:14
  • 4606

OpenGL ES着色器语言之内建函数(官方文档第八章)

OpenGL ES着色语言为标量和向量操作定义了一套内建便利函数。有些内建函数可以用在多个类型的着色器中,有些是针对固定硬件的,所以这部分只能用在某个特定的着色器上。        内建函数基本上可...
  • wangyuchun_799
  • wangyuchun_799
  • 2012年07月22日 00:33
  • 17343

自己写一个pow()函数

问题:请自己动手写一个pow()函数。   我们在学习C语言的时候,可能已经接触过pow()函数,它是C语言标准库函数中自带的一个函数,使用的时候只需包含就可以了,不需要你自己动手去实现。   在C语...
  • Enrica_Shi
  • Enrica_Shi
  • 2017年09月21日 05:50
  • 110

c++中pow函数

在C++中,pow有多个重载函数; 在dev中,pow(int,int)可以执行,但是在别的地方是不可以被编译的;会提示 :error C2668: “pow”: 对重载函数的调用不明确 ...
  • cherishwangq
  • cherishwangq
  • 2016年11月15日 10:38
  • 916

自己写一个strcmp函数(C++)

题目说明: 写一个函数,实现两个字符串的比较。即自己写一个strcmp函数,函数原型为int strcmp( char * p1, char * p2); 设p1指向字符串s1,p2指向字符串s2...
  • QianShouYuZhiBo
  • QianShouYuZhiBo
  • 2013年08月09日 21:31
  • 2657

pow函数的性能测试

昨天在PKU上做了一题2187,限时3s。 算法主要耗时在多次求不同整数的平方。 当用pow函数求时,超时; 而直接乘才232ms。 相差也太大了吧。 于是就写了一段代码来测试pow的性能 ...
  • u013445530
  • u013445530
  • 2014年08月12日 19:55
  • 1219
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:《剑指offer》:自己写一个pow函数
举报原因:
原因补充:

(最多只允许输入30个字)