首页 > 解决方案 > SymPy 中 1/x 的集成

问题描述

我认为 SymPy 在积分 1/x 时返回 log(x) 而不是 log(abs(x)) 很好。这使它变得简单,并让用户担心标志。

但是,在某些情况下它会导致错误的答案。例如,

from sympy import *
x = Symbol('x')
integrate(cos(x)**2/sin(x), x)

结果是

log(cos(x) - 1)/2 - log(cos(x) + 1)/2 + cos(x)

虽然它应该(显然?)

log(1 - cos(x))/2 - log(1 + cos(x))/2 + cos(x)

是否有一种解决方法可以产生第二个答案?

标签: pythonsympyintegral

解决方案


缺席abs不仅仅是为了“保持简单”。正如 SymPy 首席开发人员所写

SymPy 不会返回log(abs(x))for,integrate(1/x)因为它对复数无效。相反,答案在积分常数(可能很复杂)之前是正确的。默认情况下,所有 SymPy 操作都假定变量是复杂的。

其余链接问题也与您的问题有关。从某种角度来看, log(cos(x) - 1): 与积分结果一样有效log(1 - cos(x)):这两个表达式之间的差异是I*pi,它被积分常数吸收了。此外,cos(x)对于复数 x,可能大于 1,例如cos(I) = 1.54...

也就是说,以下是一种强制对数中的常数项为非负数的方法。

def fix_logs(expr):
    replacements = {}
    for a in expr.atoms(log):
        if a.args[0].as_coeff_add()[0].is_negative:
            replacements[a] = log(-a.args[0]) + log(-1)
    return expr.xreplace(replacements)

下面是它的工作原理:

rv = integrate(cos(x)**2/sin(x), x)
rv2 = fix_logs(rv)
rv3 = Add(*fix_logs(rv2).as_coeff_add(x)[1])

这里的 rv、rv2 和 rv3 是:

log(cos(x) - 1)/2 - log(cos(x) + 1)/2 + cos(x)
log(-cos(x) + 1)/2 - log(cos(x) + 1)/2 + cos(x) + I*pi/2
log(-cos(x) + 1)/2 - log(cos(x) + 1)/2 + cos(x)

该函数fix_logs不会删除 log(-1) 部分,因为它可能很重要:x*log(x-1)成为x*(log(1-x) + I*pi/2)不能简单删除常量的地方。但如果需要,可以删除附加常数,如 的计算所示rv3

as_coeff_add方法参考


推荐阅读