我在尝试使用Python创建一个简单的模拟退火搜索,但每次在使用math.exp计算指数时都会显示溢出错误。
这是我的Python代码:
import random
import math
def getF(x1, x2):
t1 = (4 - (2.1 * (x1 ** 2) + (x1 ** 4) / 3)) * (x1 ** 2)
t2 = x1 * x2
t3 = (-4 + (4 * (x2 ** 2))) * (x2 ** 2)
t = t1 + t2 + t3
return t
def getP(dE, t):
return math.exp((-1*dE)/t)
def getNewRandInRange(x):
newX = x + random.randint(-5, 5)
while (newX > 10) or (newX < -10):
newX = x + random.randint(-5, 5)
return newX
initState1 = random.randint(-10, 10)
initState2 = random.randint(-10, 10)
currentState1 = initState1
currentState2 = initState2
BSF = getF(currentState1, currentState2)
T = 1000
Tmin = 1
while T > Tmin:
print("T= %f" %T)
newState1 = getNewRandInRange(currentState1)
newState2 = getNewRandInRange(currentState2)
currentF = getF(currentState1, currentState2)
newF = getF(newState1, newState2)
print("Current X1= %f" % currentState1)
print("Current X2= %f" % currentState2)
print("New X1= %f" % newState1)
print("New X2= %f" % newState2)
dE = currentF - newF
print ("delta E: %f" %dE)
if dE > 0:
currentState1 = newState1
currentState2 = newState2
BSF = getF(newState1, newState2)
else:
randNumber = random.uniform(0, 1)
p = getP(dE, T)
if (randNumber < p):
currentState1 = newState1
currentState2 = newState2
print("BSF: %f" %BSF)
print("\n\n\n")
T = T * 0.9
print(BSF) #final output
错误信息:
Traceback (most recent call last):
return math.exp((-1*dE)/t)
OverflowError: math range error
我尝试使用try和catch,但它不会返回指数值,这会导致结果出现问题,我也尝试过在谷歌上搜索,但没有找到符合我要求的解决方案。
提前感谢您!
回答:
异常 OverflowError
当算术运算的结果太大而无法表示时会引发此异常。对于长整数(它们会引发MemoryError而不是放弃)和大多数普通整数的操作(它们会返回长整数),这种情况不会发生。由于C语言中浮点异常处理缺乏标准化,大多数浮点运算也不会被检查。 参考
您尝试计算一个大数(超过710),这超出了双精度数的范围。
您可以像这样使用try/except
来处理它:
def getP(dE, t):
try:
return math.exp((-1*dE)/t)
except:
return -1 # 或者其他任何值 :D
您可以在Python的代码中找到以下注释:
/*
* 为了简单和正确起见,我们对ndigits(系数中的总十六进制数字数)施加了一个人为的限制。
* 该限制的选择是为了确保,假设exp为指数,
*
* (1) 如果exp > LONG_MAX/2,那么十六进制字符串的值保证会溢出(前提是它非零)
*
* (2) 如果exp < LONG_MIN/2,那么十六进制字符串的值保证会下溢到0。
*
* (3) 如果LONG_MIN/2 <= exp <= LONG_MAX/2,那么在计算exp和top_exp时不会有溢出的危险。
*
* 更具体地说,ndigits被假定满足以下不等式:
*
* 4*ndigits <= DBL_MIN_EXP - DBL_MANT_DIG - LONG_MIN/2
* 4*ndigits <= LONG_MAX/2 + 1 - DBL_MAX_EXP
*
* 如果这些不等式中的任何一个不满足,将引发ValueError。否则,假设x为十六进制字符串的值,并且假设x非零。那么
*
* 2**(exp-4*ndigits) <= |x| < 2**(exp+4*ndigits)。
*
* 现在如果exp > LONG_MAX/2,那么
*
* exp - 4*ndigits >= LONG_MAX/2 + 1 - (LONG_MAX/2 + 1 - DBL_MAX_EXP)
* = DBL_MAX_EXP
*
* 所以|x| >= 2**DBL_MAX_EXP,这太大而无法存储在C的双精度数中,因此会溢出。如果exp < LONG_MIN/2,那么
*
* exp + 4*ndigits <= LONG_MIN/2 - 1 + (
* DBL_MIN_EXP - DBL_MANT_DIG - LONG_MIN/2)
* = DBL_MIN_EXP - DBL_MANT_DIG - 1
*
* 所以|x| < 2**(DBL_MIN_EXP-DBL_MANT_DIG-1),因此在转换为C的双精度数时会下溢到0。
*
* 容易证明,如果LONG_MIN/2 <= exp <= LONG_MAX/2,那么exp+4*ndigits和exp-4*ndigits都在long的范围内。
*/
无论如何,您可以使用Decimal
:
import decimal
...
def getP(dE, t):
return decimal.Decimal((-1*dE)/t).exp()