在 SymPy 中集成 1/x

Integration of 1/x in SymPy

我认为在积分 1/x 时 SymPy returns 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)

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

abs 的缺席不仅仅是为了 "keep it simple"。作为 SymPy 的首席开发人员 wrote

SymPy doesn't return log(abs(x)) for integrate(1/x) because it isn't valid for complex numbers. Instead, the answer is correct up to an integration constant (which may be complex). All SymPy operations assume that variables are complex by default.

链接问题的其余部分也与您的问题相关。从某种角度来看,log(cos(x) - 1):在积分的结果中与log(1 - cos(x))一样有效:这两个表达式之间的差异是I*pi,由积分常数吸收。此外,对于复数 x,cos(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 的计算所示。

Reference for as_coeff_add method