遗传算法运行时遇OverflowError: (34, 'Result too large')错误的解决方法
遗传算法求解参数时OverflowError的处理及Decimal转换方案
问题背景
使用遗传算法求解方程 a*x^coeff + b*x + c = 550 的5个参数时,运行代码出现 OverflowError: (34, 'Result too large') 错误,原代码如下:
import random import decimal decimal.getcontext().prec = 100 def foo (a, b, c, x, coeff): return a * x ** coeff + b * x + c - 550 def fitness (a, b, c, x, coeff): ans = foo (a, b, c, x, coeff) if ans == 0: return 99999 else: return abs (1/ans) # generate solutions solutions = [] for s in range(1000): solutions.append( (random. uniform (0, 10000), random.uniform(0, 10000), random.uniform(0, 10000), random.uniform(0, 10000), random.uniform(0,10000))) for i in range (10000): rankedsolutions = [] for s in solutions: rankedsolutions.append((fitness (s[0],s[1],s[2],s[3],s[4]),s)) rankedsolutions.sort() rankedsolutions.reverse() print (f"=== Gen {i} best solutions") print (rankedsolutions [0]) bestsolutions = rankedsolutions [:100] elements = [] for s in bestsolutions: elements.append(s[1][0]) elements.append(s[1][1]) elements.append(s[1][2]) elements.append(s[1][3]) elements.append(s[1][4]) newGen = [] for _ in range(1000): e1 = random.choice (elements) * random.uniform(0.99,1.01) e2 = random.choice (elements) * random.uniform(0.99,1.01) e3 = random.choice (elements) * random.uniform(0.99,1.01) e4 = random.choice (elements) * random.uniform(0.99,1.01) e5 = random.choice (elements) * random.uniform(0.99,1.01) newGen.append((e1,e2,e3,e4,e5)) solutions=newGen
错误核心原因是x ** coeff运算时,当x和coeff取到较大随机值(如接近10000),计算结果远超Python float类型的取值范围,触发数值溢出。
解决思路与方案
1. 临时溢出捕获方案
在核心计算函数中捕获OverflowError,返回极端值让该解被遗传算法自动淘汰:
def foo(a, b, c, x, coeff): try: return a * x ** coeff + b * x + c - 550 except OverflowError: # 返回无穷大,使对应fitness值为0,被排序到末尾 return float('inf')
fitness函数无需修改,因为abs(1/inf)结果为0,会被视为极差解,在后续迭代中被淘汰。
2. 优雅的Decimal替换方案
使用Python的decimal模块替代float,它支持更大的数值范围和可控精度,从根源避免溢出问题,具体改造步骤如下:
步骤1:封装Decimal随机数生成函数
import random import decimal decimal.getcontext().prec = 100 # 提前设置计算精度 def generate_decimal(min_val, max_val): """生成指定范围内的Decimal随机数""" return decimal.Decimal(random.uniform(min_val, max_val))
步骤2:初始化种群时使用Decimal
solutions = [] for s in range(1000): solutions.append(( generate_decimal(0, 10000), generate_decimal(0, 10000), generate_decimal(0, 10000), generate_decimal(0, 10000), generate_decimal(0, 10000) ))
步骤3:改造核心计算函数为Decimal运算
def foo(a, b, c, x, coeff): target = decimal.Decimal(550) return a * (x ** coeff) + b * x + c - target def fitness(a, b, c, x, coeff): ans = foo(a, b, c, x, coeff) if ans == decimal.Decimal(0): return decimal.Decimal(99999) else: return abs(decimal.Decimal(1) / ans)
步骤4:种群迭代时保持Decimal类型
newGen = [] for _ in range(1000): # 所有运算均使用Decimal类型 e1 = random.choice(elements) * decimal.Decimal(random.uniform(0.99, 1.01)) e2 = random.choice(elements) * decimal.Decimal(random.uniform(0.99, 1.01)) e3 = random.choice(elements) * decimal.Decimal(random.uniform(0.99, 1.01)) e4 = random.choice(elements) * decimal.Decimal(random.uniform(0.99, 1.01)) e5 = random.choice(elements) * decimal.Decimal(random.uniform(0.99, 1.01)) newGen.append((e1, e2, e3, e4, e5))
3. 遗传算法效率优化建议
- 缩小参数搜索范围:比如将
coeff的范围从0-10000调整到0-10,过大的指数必然导致数值爆炸,也不符合大多数实际方程的参数逻辑。 - 调整排序时机:原代码中每次添加一个解就排序一次,效率极低,应在所有解都添加到
rankedsolutions后再执行排序和反转操作。
内容的提问来源于stack exchange,提问作者pythonbeginner
相关产品推荐
相关产品推荐

