为什么 SymPy 的积分有时会产生非常长的反导数?

Why does SymPy's integrate sometimes produce antiderivative with very long numbers?

这是在 SymPy 1.1.1 上使用 Python 3.6.5.

在 SymPy 中,我总是不得不在被积函数周围使用 S('...') 以使其不是 return 使用浮点数的结果,有时是为了使其实际计算积分。这样做的一个副作用是 SymPy 有时 return 的结果非常长,例如

z=symbols('z')
integrate(S('1/(cos(z)+sin(z)+2**(1/2))'),z)

returns

-221108036964586978124740847487718783991180811173992192658
5647118334188786/(-2669010107947987550795474273552499757111
367990811651140108173443831125763*tan(z/2) + 
18872751463854612207095892554955468385336360233408060517004
98501499110078*sqrt(2)*tan(z/2) - 7817349615625263300858850180
569529185777319674708450884076749
42332015685*sqrt(2) + 110554018482293489062370423743859391995
5904055869960963292823559167094393) + 
1563469923125052660171770036113905837155463934941690176815349
884664031370*sqrt(2)/(-2669010107947987550795474273552499757
111367990811651140108173443831125763*tan(z/2) + 
18872751463854612207095892554955468385336360233408060517004985
01499110078*sqrt(2)*tan(z/2) - 78173496156252633008588501805695
29185777319674708450884076749
42332015685*sqrt(2) + 11055401848229348906237042374385939199559
04055869960963292823559167094393)

我验证了上面的结果是正确的。在上面做 simplify() 没有帮助。我一开始以为是结果需要简化,仅此而已。

如果我不使用 S'(....)' 和 sympy,它不会评估 这个例子。

>>> integrate(1/(cos(z)+sin(z)+2**(1/2)),z)
1.0*Integral(1/(1.0*sin(z) + 1.0*cos(z) + 1.4142135623731), z)

但与 fricas 1.3.3 的小输出相比

integrate(1/(cos(z)+sin(z)+2^(1/2)),z)
((-1)*2^(1/2)*sin(z)+((-1)*2^(1/2)*cos(z)+2))/(2*sin(z)+(-2)*cos(z))

数学 11.3

ClearAll[z]
FullSimplify[Integrate[1/(Cos[z] + Sin[z] + 2^(1/2)), z]]
-(((1 + I) + (2*I + Sqrt[2])*E^(I*z))/((1 + I) + Sqrt[2]*E^(I*z)))

枫叶2018

int(1/(cos(z)+sin(z)+2^(1/2)),z);
-2/((2^(1/2)-1)*(tan((1/2)*z)+2^(1/2)+1))

问题:SymPy的积分算法中有什么有时 使其输出如此长的数字,而其他 CAS 系统 不求同一个积分? SymPy 中有什么技巧可以使 与其他 CAS 系统相比,它产生的叶尺寸结果更小?

同样,SymPy 的结果是正确的。我只是问为什么这个例子的结果有这么长的数字。可能如果有人知道为什么,这将有助于更好地理解事情。

我可以猜到答案来自 "heuristic Risch algorithm",它在某些步骤匹配许多(拆开的)表达式的系数,并以完成这项工作的大系数结束。实际上,简化表达式 before 集成恰好有帮助:

>>> integrate(trigsimp(1/(cos(z)+sin(z)+sqrt(2))), z)
-sqrt(2)/(tan(z/2 + pi/8) + 1)

(可以在这里使用 simplify 来达到同样的效果,但是如果您知道这里需要三角化简,那么 trigsimp 就是正确的方法。)一旦表达式被简化为

sqrt(2)/(2*(sin(z + pi/4) + 1))

只剩下一个三角函数,这比处理两个容易多了。

(另外:使用 sqrt(2) 代替 2**(1/2) 是避免将 1/2 过早评估为浮点数的更好方法,而不是将整个公式字符串化。)