Sympy牛顿法求复根报错ValueError:首个变量不能为数字
解决Sympy牛顿法求解多项式复根时的ValueError问题
错误原因
核心问题是变量名冲突:你在全局定义了符号变量x,但在newton_method函数里又用x = x0把它覆盖成了数值变量。当调用f.diff(x)时,这里的x是数值(比如第一次迭代的0),而Sympy的diff方法需要传入符号变量,因此触发ValueError: First variable cannot be a number: 0。
修复后的完整代码
import sympy as sp # 定义符号变量 x = sp.symbols('x') # 定义多项式 p = x**5 + 11*x**4 - 21*x**3 - 10*x**2 - 21*x - 5 # 牛顿法参数 tolerance = 1e-5 roots = [] # 修复后的牛顿法函数:迭代变量改用x_val,避免覆盖符号x def newton_method(f, x0, tol, max_iter=100): x_val = x0 # 用x_val作为迭代数值变量,不与符号x冲突 iteration = 0 while iteration < max_iter: # 计算当前点的函数值和导数值 f_val = f.subs(x, x_val) f_deriv_val = f.diff(x).subs(x, x_val) # 避免除以0的情况 if abs(f_deriv_val) < 1e-10: return None x_next = x_val - f_val / f_deriv_val if abs(x_val - x_next) < tol: # 转换为浮点数,方便后续处理 return float(x_next) x_val = x_next iteration += 1 return None # 寻找实根,同时去重 for i in range(-10, 10): # 扩大初始值范围,避免漏根 root = newton_method(p, i, tolerance) if root is not None: # 检查是否已经在roots列表中(考虑浮点误差) if not any(abs(root - r) < tolerance for r in roots): roots.append(root) print("实根:", roots) # 约简多项式求解复根 def reduce_polynomial(poly, root): # 用sp.div进行多项式除法,更可靠 quotient, remainder = sp.div(poly, x - root) return quotient complex_roots = [] for root in roots: reduced_poly = reduce_polynomial(p, root) # 求解约简后的多项式,获取所有根 all_roots = sp.solve(reduced_poly, x) # 过滤掉已经找到的实根,只保留复根 for r in all_roots: if isinstance(r, sp.ComplexNumber) or abs(r.imag) > tolerance: complex_roots.append(r) # 去重复根 unique_complex_roots = [] for r in complex_roots: if not any(abs(r - cr) < tolerance for cr in unique_complex_roots): unique_complex_roots.append(r) print("复根:", unique_complex_roots)
关键修复点说明
- 变量名分离:将迭代用的数值变量从
x改为x_val,彻底避免与全局符号变量x冲突,这是解决报错的核心。 - 除以0防护:增加对导数值接近0的判断,避免牛顿法中出现除以0的异常。
- 实根去重:通过浮点误差判断,避免不同初始值收敛到同一个实根导致重复存储。
- 多项式除法优化:改用
sp.div进行多项式除法,比直接除法更可靠,能自动处理余数(对于精确根余数为0)。 - 复根过滤与去重:过滤掉已找到的实根,同时对复根进行去重,避免重复输出。
内容的提问来源于stack exchange,提问作者dodo
相关产品推荐
相关产品推荐

