2017-09-17 206 views
-1

我正尝试使用python创建一个简单的模拟退火搜索,但在使用math.exp计算指数时总是显示溢出错误。OverflowError:数学范围错误 - 指数Python

,这是我在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尝试,但它不会返回的阶数,它会使得结果的问题,我也试着用google搜索,但没有找到任何符合我要求的解决方案。

谢谢!

+0

可能你也发布了错误追踪记录 –

+0

你可以检查( - 1 * dE)/ t,他们可能会非常大或很小 –

回答

0

exception OverflowError

当算术运算的结果太大而无法表示时引发。对于长整数(这会引发MemoryError而不是放弃)以及对于大多数使用普通整数的操作(它们会返回长整数)不会发生这种情况。由于C中缺少浮点异常处理的标准化,大多数浮点操作也不会被检查。 Ref

您试图计算一个大数字(大于710),并且超出了double范围。

你可以try/except这样的处理:

def getP(dE, t): 
    try: 
     return math.exp((-1*dE)/t) 
    except: 
     return -1 # or anything else :D 

你可以在Python的代码此评论:

/* 
* For the sake of simplicity and correctness, we impose an artificial 
* limit on ndigits, the total number of hex digits in the coefficient 
* The limit is chosen to ensure that, writing exp for the exponent, 
* 
* (1) if exp > LONG_MAX/2 then the value of the hex string is 
* guaranteed to overflow (provided it's nonzero) 
* 
* (2) if exp < LONG_MIN/2 then the value of the hex string is 
* guaranteed to underflow to 0. 
* 
* (3) if LONG_MIN/2 <= exp <= LONG_MAX/2 then there's no danger of 
* overflow in the calculation of exp and top_exp below. 
* 
* More specifically, ndigits is assumed to satisfy the following 
* inequalities: 
* 
* 4*ndigits <= DBL_MIN_EXP - DBL_MANT_DIG - LONG_MIN/2 
* 4*ndigits <= LONG_MAX/2 + 1 - DBL_MAX_EXP 
* 
* If either of these inequalities is not satisfied, a ValueError is 
* raised. Otherwise, write x for the value of the hex string, and 
* assume x is nonzero. Then 
* 
* 2**(exp-4*ndigits) <= |x| < 2**(exp+4*ndigits). 
* 
* Now if exp > LONG_MAX/2 then: 
* 
* exp - 4*ndigits >= LONG_MAX/2 + 1 - (LONG_MAX/2 + 1 - DBL_MAX_EXP) 
*     = DBL_MAX_EXP 
* 
* so |x| >= 2**DBL_MAX_EXP, which is too large to be stored in C 
* double, so overflows. If exp < LONG_MIN/2, then 
* 
* exp + 4*ndigits <= LONG_MIN/2 - 1 + (
*      DBL_MIN_EXP - DBL_MANT_DIG - LONG_MIN/2) 
*     = DBL_MIN_EXP - DBL_MANT_DIG - 1 
* 
* and so |x| < 2**(DBL_MIN_EXP-DBL_MANT_DIG-1), hence underflows to 0 
* when converted to a C double. 
* 
* It's easy to show that if LONG_MIN/2 <= exp <= LONG_MAX/2 then both 
* exp+4*ndigits and exp-4*ndigits are within the range of a long. 
*/ 

无论如何,你可以使用Decimal

import decimal 
... 
def getP(dE, t): 
    return decimal.Decimal((-1*dE)/t).exp() 
+0

如前所述,我不能使用try和catch因为它会返回一个意想不到的数字,这会导致问题(在本例中为-1),但可以我整数,所以数字不会超过数字限制? –

+0

@YogiWisesa我更新了我的答案;)您可以在这种情况下使用小数 – RaminNietzsche