我正在用Python编写程序,我需要找到一个函数的导数(以字符串表示的函数)。
x^2+3*x
2*x+3
有可用的脚本吗,或者有什么有用的可以告诉我吗?
如果您仅限于多项式(似乎是这种情况),则基本上分为三个步骤:
如果您需要处理像
a*x^15125 + x^2 + c
这样的多项式,则使用 dict
作为系数列表可能有意义,但在通过此列表进行迭代时需要多加注意。
您可能会在已经提供的答案中找到您想要的内容。然而,我想对如何计算符号导数给出一个简短的解释。
该业务基于算子重载和衍生品的链式法则。例如,
v^n
的导数是n*v^(n-1)dv/dx
,对吗?那么,如果你有 v=3*x
和 n=3
,导数会是什么?答案:如果f(x)=(3*x)^3
,则导数为:
f'(x)=3*(3*x)^2*(d/dx(3*x))=3*(3*x)^2*(3)=3^4*x^2
链式法则允许您“链接”操作:每个单独的导数都很简单,而您只需“链接”复杂性。再比如,
u*v
的导数是v*du/dx+u*dv/dx
,对吧?如果你得到一个复杂的函数,你只需将它链接起来,说:
d/dx(x^3*sin(x))
u=x^3; v=sin(x)
du/dx=3*x^2; dv/dx=cos(x)
d/dx=v*du+u*dv
如您所见,微分只是一系列简单的操作。
现在,运算符重载。
如果您可以编写一个解析器(尝试 Pyparsing),那么您可以要求它评估函数和导数!我这样做(使用 Flex/Bison)只是为了好玩,而且它非常强大。为了让您明白这个想法,导数是通过重载相应的运算符并递归地应用链式法则来递归计算的,因此
"*"
的计算将对应于函数值的 u*v 和导数值的 u*der(v)+v*der(u)
(尝试用C++写的,也很有趣)。
所以,我知道您并不是要编写自己的解析器 - 无论如何都要使用现有代码(访问 www.autodiff.org 以自动区分 Fortran 和 C/C++ 代码)。但了解这些东西是如何工作的总是很有趣。
迟到总比不到好?
我总是通过使用解析树来完成任何语言的符号微分。 但我最近也意识到另一种使用复数的方法。
解析树方法包括将以下微小的 Lisp 代码翻译成您喜欢的任何语言:
(defun diff (s x)(cond
((eq s x) 1)
((atom s) 0)
((or (eq (car s) '+)(eq (car s) '-))(list (car s)
(diff (cadr s) x)
(diff (caddr s) x)
))
; ... and so on for multiplication, division, and basic functions
))
然后使用适当的简化器,这样你就可以去掉 0 加法、乘以 1 等。
但是复杂的方法虽然完全是数字的,但具有一定的神奇品质。不要以双精度对计算 F 进行编程,而以双精度复数进行。 然后,如果需要计算变量 X 的导数,请将 X 的虚部设置为非常小的数字 h,例如 1e-100。 然后进行计算,得到结果R。 现在 real(R) 是您通常会得到的结果,而 imag(R)/h = dF/dX 精度非常高!
它是如何运作的?以复数相乘为例:
(a+bi)(c+di) = ac + i(ad+bc) - bd
现在假设虚部全部为零,但我们需要相对于
a
的导数。
我们将 b
设置为一个非常小的数字 h
。现在我们得到了什么?
(a+hi)(c) = ac + hci
因此,如您所料,其实部为
ac
,虚部除以 h
为 c
,它是 ac
相对于 a
的导数。
同样的推理似乎适用于所有微分规则。
您可以尝试创建一个严格表示极限的类,然后当 x 接近 a 时评估它的 (f(x)-f(a))/(x-a)。这应该给出一个非常准确的极限值。
如果您使用字符串作为输入,则可以使用 + 或 - 字符作为分隔符来分隔各个术语,这将为您提供各个术语。现在您可以使用幂法则来求解每个项,假设您有 x^3,使用幂法则将为您提供 3x^2,或者假设您有一个更复杂的项,例如 a/(x^3) 或 a(x^ -3),同样,您可以将其他变量选为常量,现在求解 x^-3 将得到 -3a/(x^2)。单独的幂法则就足够了,但是它需要广泛使用因式分解。
除非任何已经制作的库派生它非常复杂,因为您需要解析和处理函数和表达式。
自行推导它是一项简单的任务,因为它是机械的并且可以通过算法完成,但您需要一个基本结构来存储函数。