使用数值算法进行指数函数的编写,满足【所有正实数为底数,任意实数为指数的指数函数计算】
本程序,使用规范化的编程【注释,分段,变量定义,常量定义】
使用牛顿迭代法计算N次方根,并且初始值采用自动计算。
程序运行结果:
Please Input the Power Number:989
Please Input the Power Index:12.333
You have input fbaseNum, PowerIndex 989 12.333
power(989.00000000000000 , 12.33300000000000)=8.7047412120061421392e+36
计算器运行的结果:
8.7047412120061422565207046539945e+36
有效数字达到16位
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# Author:@MikeLiu
# Date 2020-02-20
import decimal
def FMatF_TEN(x):
return decimal.Decimal("%.14f" % float(x))
'''
'定义常量,确定计算的精度'
'''
ELPSILON = FMatF_TEN(1.0e+13) ## 设置小数转分数的 精度范围
INFINUM = FMatF_TEN(1.7e+307) ## 设置最大计算值
ELPS = FMatF_TEN(1.0e-13) ## 求N次方根的 精度控制
ELPS_E = FMatF_TEN(0.005) ## 求N次方根时 初值的控制范围
ZERO = 0
ONE = 1
###############################################################
def Is_Prime(iNum_a, iNum_b): ## 判断两个数字是否互质
while iNum_b != ZERO:
iNum_a, iNum_b = (iNum_b, iNum_a%iNum_b)
return iNum_a
###############################################################
class CPowerE: ## Caclulate the Power(fBase,iIndex)
def powerE(self,fbase,iexponent): ## 计算整数指数函数值
flag=ONE
Ret=FMatF_TEN(1.0)
tmp=fbase
if iexponent==ZERO: ## 指数为 0 结果为 1
return ONE
if iexponent<ZERO: ## 指数为 负数 按照正数计算,结果取倒数【参看最后返回结果】
flag=ZERO ## 定义标志位 flag 【0:负数; 1:正数】
iexponent=abs(iexponent)
while iexponent>ZERO:
if iexponent&1==ONE: ## 指数 跟 1 做与运算,判断是奇数,则乘以底数
Ret=Ret*tmp
iexponent>>=ONE ## 指数 跟 1 做与运算,判断是偶数,底数的平方,并且指数右移【相当于除以2取整】
tmp=tmp*tmp
if(tmp>INFINUM): ## 如果乘出来的超过最大数 INFINUM 就取最大值
tmp=INFINUM
return Ret if flag else 1/Ret ## 最后返回计算结果,并且判断标志位,根据正负情况取值
def powerW(self,fbase,n): ## 求 M 的 N次方根 函数 【牛顿迭代算法,自动设置初值】
X = fbase /n ## 初始值默认取法
iTemp = 0
if(X < ELPS_E): ## 初始值过小,则取自己本身 (数值除以 n 所以不会出现大数值)
X = fbase/2
while (X!=ZERO):
iTemp = X
'''
' 牛顿迭代算法,请参看网址:https://www.cnblogs.com/houkai/p/3332520.html'
'''
U_1 = FMatF_TEN(self.powerE(X,n))-FMatF_TEN(fbase)
if(U_1>INFINUM):
U_1=INFINUM
U_2 = FMatF_TEN(n*self.powerE(X,n-1))
if(U_2==0):
U_2=X ## 如果精度控制,导致计算出的过程值变成0 则取 X 代替
elif(U_2>INFINUM):
U_2=INFINUM ## 如果精度控制,导致计算出的过程值变成无穷大 则取 INFINUM 代替
X = X - U_1/(U_2)
if((abs(X - iTemp) < ELPS)):
return X
###############################################################
class CDecToFract: ## 小数转换成分带数 格式 【整数,分子,分母】 3.25=3+1/4=[3, 1, 4]
def DecToFract(self,fPoint):
Data=[]
Data.append(int(fPoint)) ## 取整放在数组 Data[] 第一个位置 Data[0]
fDeci = FMatF_TEN(fPoint - Data[0]) ## 取小数部分
iNum_a = int(fDeci*ELPSILON) ## 小数部分放大 ELPSILON 倍数作为分子初始值
iNum_b = int(ELPSILON) ## ELPSILON 本身作为分母初始值
itmp = Is_Prime(iNum_a, iNum_b) ## 判断分子分母是否互质
while (1 != itmp): ## 如果不互质,采用辗转相除法,进行约分化简
iNum_a /= itmp
iNum_b /= itmp
itmp = Is_Prime(iNum_a, iNum_b)
Data.append(int(iNum_a)) ## 分子放在数组 Data[] 第二个位置 Data[1]
Data.append(int(iNum_b)) ## 分母放在数组 Data[] 第三个位置 Data[2]
return Data
###############################################################
'''
' 指数函数的基本计算法则: '
' power(3,2.75) = power(3,2+3/4) = power(3,2) * power(3,3/4) = power(3,2)*power(power(3,1/4),3) = 20.51556351259'
'''
def power(fbase,iexponent): ## Calulate 指数函数的计算方式
Dect=CDecToFract()
fNum=FMatF_TEN(fbase) ## 输入数值,取十位有效数字
iIndex=FMatF_TEN(iexponent) ## 输入数值,取十位有效数字
ARet=Dect.DecToFract(iIndex) ## 通过小数化分数的类处理指数参数
PowerE = CPowerE()
if(ARet[1]==0): ## 如果分子是0 直接使用指数计算类,调用整数的指数函数计算法
return PowerE.powerE(fNum,int(iIndex))
else: ## 如果分子不是0 整数部分调用整数的指数函数计算法,分母用底数的方根计算,分支用方根计算后的整数计算,最后做乘法
A=PowerE.powerE(fNum,int(ARet[0]))
B=PowerE.powerW(fNum,int(ARet[2]))
C=PowerE.powerE(B,int(ARet[1]))
Ret=A*C
return Ret
if __name__ == '__main__':
fNum=input("\n\nPlease Input the Power Number:")
iIndex=input("Please Input the Power Index:")
print("\nYou have input fbaseNum, PowerIndex",fNum,iIndex)
fNum = FMatF_TEN(fNum)
iIndex = FMatF_TEN(iIndex)
Ret = '%.20g'%(power(fNum,iIndex)) ## 科学计数法 保留20位有效数字
print ("power(",fNum," , ", iIndex,")","=",Ret,sep='')