使用SymPy求解[-1,1]区间内函数极值的报错问题
报错原因与解决办法
报错原因
- 虚部过滤逻辑失效:原代码用
sp.im(soln[i])!=0筛选复根,但SymPy求解一阶导数时,部分实际为实根的解会附带极小虚部(如-7.09593646502773 + 0.e-20*I),这一虚部不等于0,导致这些根未被过滤。后续用非严格实数做大小比较时,触发SymPy的类型错误。 - 函数表达式笔误:原代码将题目中的
10ˣ写成了10*x,导致函数定义错误,导数计算也会偏离需求。 - 区间注释与需求不符:代码注释标注“0到1”,但实际需求是区间
[-1,1],虽不直接引发报错,但需修正以匹配需求。
解决方法
- 修改复根过滤规则:判断根的虚部绝对值是否小于题目指定的阈值
1×10⁻¹⁵,若满足则视为实根,提取其实部作为有效解。 - 修正函数表达式:将
10*x改为10**x,匹配题目中的10ˣ。 - 统一数值形式比较:将处理后的实根转为数值后再做区间判断,避免SymPy符号对象的比较冲突。
修正后的代码
import sympy as sp x = sp.symbols('x') # 定义正确的函数表达式 y = x**4 - 100*x**2 + 10**x - 2 # 计算一阶导数 diff1 = sp.diff(y, x, 1) # 计算二阶导数 diff2 = sp.diff(y, x, 2) # 求解一阶导数的根 soln = sp.solve(diff1) # 筛选区间[-1,1]内的有效实根 soln1 = [] threshold = 1e-15 # 题目指定的虚部忽略阈值 for root in soln: # 判断虚部是否可忽略 imag_part = sp.im(root) if abs(imag_part) > threshold: continue # 提取实根并转为数值 real_root = sp.re(root).evalf() # 判断是否在目标区间内 if -1 <= real_root <= 1: soln1.append(real_root) # 求解极大值与极小值 if soln1: for pt in soln1: # 计算二阶导数在该点的数值 diff2_val = diff2.subs(x, pt).evalf() # 判断极大值 if diff2_val < 0: max_val = y.subs(x, pt).evalf() print(f'函数在点 {pt} 处取得极大值:{max_val}') # 判断极小值 elif diff2_val > 0: min_val = y.subs(x, pt).evalf() print(f'函数在点 {pt} 处取得极小值:{min_val}') else: print("给定区间内无极大值或极小值。")
关键修改说明
- 修正函数笔误:将
10*x改为10**x,确保与题目中的函数一致。 - 优化复根过滤:用
abs(sp.im(root)) > threshold替代原逻辑,正确识别带有极小虚部的实根。 - 数值化处理:将实根转为数值后再做区间判断,避免符号对象的比较错误。
内容的提问来源于stack exchange,提问作者Ovilash moitra
相关产品推荐
相关产品推荐

