數值的整數次方(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.
數值的整數次方(C++ 和 Python 實現)