### OverflowError: 数学范围错误 – Python中的指数运算

我在尝试使用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()

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注