最近,我使用sympy和cos(x)作为一个复杂的函数,发现提供的参数函数arg
和atan2
函数会产生不同的结果。通过绘制结果可以很容易地显示出来。
import sympy as sp
c = sp.cos(x)
sp.plot(sp.atan2(sp.im(c),sp.re(c)))
sp.plot(sp.arg(c))
虽然差异只是pi的自然倍数,但我希望这两个函数都能返回上图。这也是WolframAlpha产生的结果,请参阅arg和atan2。 有趣的是,如果我在数值上计算参数(使用sympy函数),我得到了预期的结果:
import numpy as np
import matplotlib.pyplot as plt
xv = np.linspace(-10,10,200)
plt.plot(xv,[sp.arg(i) for i in np.cos(xv)])
有人可以,请指出差异,也许是一个合理的解决方案,以获得相同的结果?
我使用了sympy 0.7.5。
答案 0 :(得分:3)
不同的情节来自于同情中的优化。当你绘制一些东西时,sympy在内部使用numpy来评估你的功能。 sympy的函数vectorized_lambdify
将arg(cos(x))
转换为它的numpy等价物,np.angle(np.cos(x))
,然后sympy会为适当的numpy数组求值。所以同情的事情大致相当于
import numpy as np
import matplotlib as plt
xv = np.array(np.linspace(-10,10,200), dtype=np.complex)
plt.plot(xv, np.angle(np.cos(xv)))
这会重现从-pi到pi的跳转。有关sympy中重要的代码行,请参阅here。
使用atan的另一个变体被重写为
np.arctan2(-np.sin(np.real(x))*np.sinh(np.imag(x)),
np.cos(np.real(x))*np.cosh(np.imag(x)))
相当于numpy的definition of angle,并且确实绘制了这个也是跳跃的特征。因此,从我的角度来看,更重要的问题是:为什么sp.atan2(..)
的情节看起来不同?
我还没有找到原因,但我相信这可能会超出你问题的范围?!回答你的问题:
如果你想得到相同的结果,最简单的版本可能是绘制模2pi。或者,通过直接从numpy绘制类似experimental_lambdify
的内容来避免lambda val: (expr).subs(x, val)
调用,或者完全替换lambdify:在运行第一个示例之前执行以下代码,两个绘图看起来都像上面的那样:
import sympy.plotting.experimental_lambdify sympy.plotting.experimental_lambdify.experimental_lambdify = lambda x, exp, **kwargs: vectorize(lambda val: exp.subs(x[0], val))
(请注意,此版本的代码段仅适用于1d图。)
答案 1 :(得分:0)
这可能是预期的行为。参数通常被认为是从-pi到pi,因为复平面中的分支切割发生在负实轴而不是正实轴