zoukankan      html  css  js  c++  java
  • 数值的整数次方(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() << '
    ';
        }
    }
    
    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.
    ");
        else
            printf("Test failed.
    ");
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        // 底数、指数都为正数
        printf("Test1 begins.
    ");
        Test(2, 3, 8, false);
    
        // 底数为负数、指数为正数
        printf("Test2 begins.
    ");
        Test(-2, 3, -8, false);
    
        // 指数为负数
        printf("Test3 begins.
    ");
        Test(2, -3, 0.125, false);
    
        // 指数为0
        printf("Test4 begins.
    ");
        Test(2, 0, 1, false);
    
        // 底数、指数都为0
        printf("Test5 begins.
    ");
        Test(0, 0, 1, false);
    
        // 底数为0、指数为正数
        printf("Test6 begins.
    ");
        Test(0, 4, 0, false);
    
        // 底数为0、指数为负数
        printf("Test7 begins.
    ");
        Test(0, -4, 0, true);
    
        return 0;
    }

    5. 参考代码下载

    项目 11_Power 下载: 百度网盘

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

     

    参考资料

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

     

  • 相关阅读:
    个人日志-6.27
    <软件工程>课程总结
    团队项目--地铁信息查询-UML图初步设计
    7-4 日报
    7-5小组日报 最终版的发布
    7-1 7-3
    软工日报6-30
    软工日报 6-29
    6-28小组会议记录
    6-27小组讨论内容
  • 原文地址:https://www.cnblogs.com/klchang/p/8283908.html
Copyright © 2011-2022 走看看