SymPy中如何将solveset求解的三次方程解转为有理形式?
问题:将SymPy求解三次方程的冗长解转为简洁有理形式
原需求是求解含参数a的三次方程的x值,初始表达式为:
poly = b*(-(10 + x)*b - 10*b) - ((8/3) + x)*((10+x)*(1+x) - 10)
其中:
b = sp.sqrt((8/3)*(1 - a))
该式可化简为有理系数三次多项式:
$x³ + \frac{41}{3}x² + \frac{8}{3}(a + 10)x + \frac{160}{3}(a - 1)$
使用SymPy的solveset()求解后,解因大量重复分数显得十分冗长。尝试直接用Rational()转换解集合时触发报错:
import sympy as sp from sympy import Eq, solveset, Rational from sympy.abc import x, a, b poly = b*(-(10 + x)*b - 10*b) - ((8/3) + x)*((10+x)*(1+x) - 10) polysub = poly.subs(b,sp.sqrt((8/3)*(1 - a))) polyeq = Eq(polysub,0) solutionset = solveset(polyeq,x) Rational(solutionset)
报错信息:
TypeError: invalid input: {ridiculously long solution}
解决方案
核心问题分析
Rational()仅能转换单个数值或表达式,无法直接作用于solveset()返回的集合对象,这是报错的直接原因。要得到简洁的有理形式解,需从方程预处理和解的逐个化简两方面入手:
步骤1:预处理方程,避免冗余根号
直接代入b后求解会引入大量根号,导致解的结构冗余。建议直接使用你已化简好的有理系数三次多项式,或通过平方消去根号后化简:
# 方式1:直接使用化简后的三次多项式 simplified_poly = x**3 + Rational(41,3)*x**2 + Rational(8,3)*(a+10)*x + Rational(160,3)*(a-1) polyeq = Eq(simplified_poly, 0) # 方式2:从原始表达式出发,平方消去根号后化简 polysub_simplified = sp.expand(polysub**2) polysub_simplified = sp.cancel(polysub_simplified) polyeq = Eq(polysub_simplified, 0)
步骤2:逐个化简集合中的解
将solveset()返回的集合转为列表,遍历每个解使用nsimplify()(指定有理数模式)进行化简,自动将浮点数转为精确有理数并合并同类项:
solutions = list(solutionset) # 对每个解进行有理化化简,指定参数a为符号变量保留 simplified_solutions = [sp.nsimplify(sol, [a]) for sol in solutions]
步骤3:可选:因式分解优化结构
如果解的结构允许,可进一步用factor()分解表达式,让形式更简洁:
simplified_solutions = [sp.factor(sp.nsimplify(sol, [a])) for sol in solutions]
完整修正代码
import sympy as sp from sympy import Eq, solveset, Rational from sympy.abc import x, a, b # 使用化简后的三次多项式构建方程 simplified_poly = x**3 + Rational(41,3)*x**2 + Rational(8,3)*(a+10)*x + Rational(160,3)*(a-1) polyeq = Eq(simplified_poly, 0) solutionset = solveset(polyeq, x) # 遍历并化简每个解 simplified_solutions = [sp.nsimplify(sol, [a]) for sol in list(solutionset)] # 打印简化后的解 for idx, sol in enumerate(simplified_solutions): print(f"解 {idx+1}:") sp.pprint(sol)
内容的提问来源于stack exchange,提问作者null_set
相关产品推荐
相关产品推荐

