数值的整数次方(C++ 和 Python 实现)

(说明:本博客中的题目题目详细说明参考代码均摘自 “何海涛《剑指Offer:名企面试官精讲典型编程题》2012年”)

题目

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

算法设计思想

  无论是简单直接方法,还是高效的方法,都需要首先全面考虑 base 和 exponent 的可能的输入:正数、负数和 0。实现的基本思想是把数值的整数次方,转化为数值的非负整数次方,然后根据指数的符号,再做相应处理,具体如下:

  假设求解 a 的 n 次方,在指数 n 为正整数的前提下,简单直接方法就是将结果依次,就将结果乘以 base 几次,此时算法的时间复杂度为 O(n);

  高效算法利用下面的公式,此时算法的时间复杂度为 O(logn)。

  若指数 n 为负整数,则可先求 a 的 -n 次方,最后将计算结果取倒数,即可。此时需要注意,分母不能为 0,即 a 的 -n 次方的结果不能为 0,也就是说,当 n 为负整数时,a 不能为 0。

  若指数 n 为 0 时,只要 a 不等于 0,则计算结果为 1;若 a 为 0 时,则为 0 的 0 次方,没有意义。

注:
  易错点,将浮点数(float 或 double)使用 == 符号与 0 直接比较,以判断此数值是否为 0。因为浮点数在计算机中的表示是有误差的,所以不是直接使用 == 符号判断某浮点数是否为 0。在实现时,往往需要判断浮点数是否在数值 0.0 附近的小范围之内,若是,则判定此数值为 0。本博文中,取 10 的 -7 次方(1e-7)作为误差范围。

C++ 实现

/*
* Author: klchang
* Date: 2018.1.14
* Description: Compute the integer power of a numeric value.
*/

#include <iostream>
#include <exception>

// Exception class for invalid input: base = 0 when exponent is negative.
class InvalidInputException: public std::exception {
    // virtual function does not throw any exception
    virtual const char* what() const throw()
    {
        return "Invalid input exception happened.";
    }

} invalid_input;

// power function with non-negative exponent in the common method
// parameters:
//    base - <0, =0, >0; exponent - =0 or >0
double power_common(double base, unsigned int exponent)
{
    double result = 1;

    for (int i = 0; i < exponent; ++ i) {
        result *= base;
    }

    return result;
}

// power function with non-negative exponent in the common method
// parameters:
//     base - <0, =0, >0; exponent - =0 or >0.
double power_fast(double base, unsigned int exponent)
{
    double result = 1;

    if (0 == exponent)
        return 1;
    else if (1 == exponent)
        return base;
    else {
        // odd number
        result = power_fast(base, exponent >> 1);
        if (exponent & 1) {
            // odd number
            return result * result * base;
        } else {
            // even number
            return result * result;
        }
    }
}

// Check if a double value is zero
bool is_zero(double value)
{
    double zero_limit = 1e-7;

    return (value >= -1 * zero_limit) && (value <= zero_limit);
}

// generic interface for power function with integer exponent including positives, zero and negatives
// parameters:
//     method: 1 -- fast method; others -- common method
double Power(double base, int exponent, int method=0)
{
    int sign = 1;  // default: positive exponent
    double result;

    if (exponent <= 0) {
        if (is_zero(base)) {   // fallibility: use 0 == base(double type)
            // illegal input: 0^0  no meaning; 0^negative_integer error
            throw invalid_input;
        }
        sign = -1;
        exponent = - exponent;
    }

    if (1 == method) // fast method
        result = power_fast(base, (unsigned int)exponent);
    else  // common method
        result = power_common(base, (unsigned int)exponent);

    if (sign < 0) {
        result = 1.0 / result;
    }

    return result;
}

void unitest()
{
    try {
        std::cout << "---------------- Power function in Fast Method Test ----------------" << std::endl
                  << "The result of -2^-3 is " << Power(-2, -3, 1) << std::endl
                  << "The result of -2^3 is " << Power(-2, 3, 1) << std::endl
                  << "The result of 2^-3 is " << Power(2, -3, 1) << std::endl
                  << "The result of 2^3 is " << Power(2, 3, 1) << std::endl;
        std::cout << "---------------- Power function in Common Method Test ----------------" << std::endl
                  << "The result of -2^-3 is " << Power(-2, -3) << std::endl
                  << "The result of -2^3 is " << Power(-2, 3) << std::endl
                  << "The result of 2^-3 is " << Power(0, -3) << std::endl
                  << "The result of 2^3 is " << Power(2, 3) << std::endl;
    }
    catch(std::exception& e) {
        std::cerr << e.what() << ‘\n‘;
    }
}

int main()
{
    unitest();

    return 0;
}

Python 实现

#!/usr/bin/python
# -*- coding: utf8 -*-
"""
# Author: klchang
# Date: 2018.1.14
# Description: Compute the integer power of a numeric value.
"""

# Invalid input exception class
class InvalidInput(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

# power function with non-negative exponent in the common method
def power_common(base, exponent):
    result = 1

    for i in range(exponent):
        result *= base;

    return result

# power function with non-negative exponent in the fast method
def power_fast(base, exponent):
    if 0 == exponent:
        return 1
    elif 1 == exponent:
        return base
    else:
        result = power_fast(base, exponent >> 1)
        if exponent & 1:
            # odd integer
            return result * result * base
        else:
            # even integer
            return result * result

# Check if value (int/float) is zero
# parameters:
#   value - int type or float type
def is_zero(value):
    # Check the type that value belongs to
    if isinstance(value, float):
        # float type
        zero_limit = 1e-7
        return (value >= -zero_limit) and (value <= zero_limit)
    else:
        # int type
        return value == 0

# Generic interface for power function with integer exponent including positives, zero and negatives
# parameters:
#     method: 1 -- fast method; others -- common method
def power(base, exponent, method=0):
    # sign flag: positive(default)
    is_positive_exponent = True
    if exponent <= 0:
        if is_zero(base):
            raise InvalidInput(base)
        exponent = - exponent
        is_positive_exponent = False
    # computation result
    result = 0
    if 1 == method:
        result = power_fast(base, exponent)
    else:
        result = power_common(base, exponent)
    # check the sign of the exponent
    if not is_positive_exponent:
        result = 1.0 / result

    return result

def unitest():
    try:
        print("---------------- Power function in Fast Method Test ----------------")
        print("The result of -2^-3 is %f." % power(-2, -3, 1))
        print("The result of -2^3 is %f." % power(-2, 3, 1))
        print("The result of 2^-3 is %f." % power(2, -3, 1))
        print("The result of 2^3 is %f."% power(2, 3, 1))
        print("---------------- Power function in Common Method Test ----------------")
        print("The result of -2^-3 is %f." % power(-2, -3))
        print("The result of -2^3 is %f." % power(-2, 3))
        print("The result of 2^-3 is " % power(0, -3))
        print("The result of 2^3 is " % power(2, 3))
    except Exception as e:
        print("Invalid input exception happened: input %s with negative exponent" % e)

if __name__ == ‘__main__‘:
    unitest()

参考代码

1. targetver.h

#pragma once

// The following macros define the minimum required platform.  The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application.  The macros work by enabling all features available on platform versions up to and
// including the version specified.

// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.
#endif

2. stdafx.h

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

// TODO: reference additional headers your program requires here

3. stdafx.cpp

// stdafx.cpp : source file that includes just the standard includes
// Power.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"

// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

4. Power.cpp

// Power.cpp : Defines the entry point for the console application.
//

// 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛

#include "stdafx.h"
#include <math.h>

bool g_InvalidInput = false;
bool equal(double num1, double num2);
double PowerWithUnsignedExponent(double base, unsigned int exponent);

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;
}
*/
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;
}

bool equal(double num1, double num2)
{
    if((num1 - num2 > -0.0000001)
        && (num1 - num2 < 0.0000001))
        return true;
    else
        return false;
}

// ====================测试代码====================
void Test(double base, int exponent, double expectedResult, bool expectedFlag)
{
    double result = Power(base, exponent);
    if(abs(result - expectedResult) < 0.00000001
        && g_InvalidInput == expectedFlag)
        printf("Test passed.\n");
    else
        printf("Test failed.\n");
}

int _tmain(int argc, _TCHAR* argv[])
{
    // 底数、指数都为正数
    printf("Test1 begins.\n");
    Test(2, 3, 8, false);

    // 底数为负数、指数为正数
    printf("Test2 begins.\n");
    Test(-2, 3, -8, false);

    // 指数为负数
    printf("Test3 begins.\n");
    Test(2, -3, 0.125, false);

    // 指数为0
    printf("Test4 begins.\n");
    Test(2, 0, 1, false);

    // 底数、指数都为0
    printf("Test5 begins.\n");
    Test(0, 0, 1, false);

    // 底数为0、指数为正数
    printf("Test6 begins.\n");
    Test(0, 4, 0, false);

    // 底数为0、指数为负数
    printf("Test7 begins.\n");
    Test(0, -4, 0, true);

    return 0;
}

5. 参考代码下载

项目 11_Power 下载: 百度网盘

何海涛《剑指Offer:名企面试官精讲典型编程题》 所有参考代码下载:百度网盘

参考资料

[1] 何海涛. 剑指 Offer:名企面试官精讲典型编程题 [M]. 北京:电子工业出版社,2012. 84-93.

原文地址:https://www.cnblogs.com/klchang/p/8283908.html

时间: 2024-10-10 03:37:00

数值的整数次方(C++ 和 Python 实现)的相关文章

【剑指offer】数值的整数次方

转载请注明出处:http://blog.csdn.net/ns_code/article/details/25506085 剑指offer上的第十一题,九度OJ上测试通过. 题目描述: 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 输入: 输入可能包含多个测试样例.对于每个输入文件,第一行输入一个整数T,表示测试案例的数目,接下来的T行每行输入一个浮点数base和一个整数exponent,两个数中间用一个空格隔开. 输出: 对应每

数值的整数次方-剑指Offer

数值的整数次方 题目描述 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 思路 主要有几点需要注意 由于计算机表示小数(float和double)都有误差,不能直接用等号(==)判断两个小数是否相等.若两个小数的差的绝对值很小,比如小于0.0000001,就可以认为它们相等 注意考虑输入值得全面性,正负可能,而且0的负数次幂没意义. 代码 解法一: public class Solution { public double Powe

《剑指Offer》题目:数值的整数次方

题目描述:数值的整数次方给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 题目分析:题目的关键在于要考虑exponent为负数的情况. Java代码: public class Power { public static double power(double base, int exponent) { double res = 1.0; if(exponent == 0){ return 1.0; } if(exponent > 0

[剑指offer]Q11:数值的整数次方

pow(base, exponent) 考虑一下几种情况: base = 0, 那么直接返回0 base = 1, 那么直接返回1 exponent = 0, 那么直接返回1, 注意base= 0 exponent = 1, 那么直接返回 base exponent  为正为负 的情况 主要考察的点是将问题缩减,用折半的思想.这个题细节还是很多的,为了便于验证,leetcode上恰好有这个题,建议在线AC一下. def equal(self, a, b): return abs(a - b) <

c++实现数值的整数次方(类似pow())作用

/* * 计算数值的整数次方.cpp * * Created on: 2018年4月13日 * Author: soyo */ #include<iostream> #include<math.h> #include<ctime> using namespace std; int main() { double power(double base,int exp); int x=2,y=3; long int z; z=pow(2,3); cout<<&qu

剑指Offer--第16题 数值的整数次方

第16题 数值的整数次方 题目:给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 思路 看到有点懵,第一感觉觉得是不是应该考虑0的0次或者负数情况,还有就是浮点类型没办法使用"="号,最后自己以偷懒的方式直接调用Java的API,如果面试题中不让调用库函数,那么基本上这题就是挂了可能. 以上题目描述来自牛客,没有对使用做限制.真正的剑指offer上有限制条件不得使用库函数,同时不需要考虑大数问题. 自己的low代码 publ

面试题16:数值的整数次方

// 面试题16:数值的整数次方 // 题目:实现函数double Power(double base, int exponent),求base的exponent // 次方.不得使用库函数,同时不需要考虑大数问题. 解题思路: 解题并不难,重要的是要考虑到输入的各种情况,并且有相应的处理. double和int都是可以取负数和0的,如果base取0,exponent<0,结果显然是不存在的. base取0,exponent取非负,直接返回1就可以了. 其他情况,正常运算就好,要注意如果expo

《剑指offer》第十六题(数值的整数次方)

// 面试题:数值的整数次方 // 题目:实现函数double Power(double base, int exponent),求base的exponent // 次方.不得使用库函数,同时不需要考虑大数问题. #include <iostream> #include <cmath> using namespace std; bool g_InvalidInput = false;//使用全局变量作为错误处理方式 bool equal(double num1, double nu

剑指Offer对答如流系列 - 数值的整数次方

面试题15:数值的整数次方 题目描述 实现函数double Power(double base, int exponent),求base的exponent次方.不得使用库函数,同时不需要考虑大数问题. 问题分析 三思而后行,这道题如果没事实现考虑好,非常容易出错. 首先分析列举出所有的场景. base的值 可能为正数也可能为负数(包含整数.小数) exponent的值可能为正整数也可能为负整数 base的值的处理是比较简单的,对于exponent的处理就要多加考虑了. 当exponent的值为负