數值的整數次方(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.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM