这篇文章主要是记录一下在回答贴吧上这个问题时所发现的关于Mathematica求导的一些坑。
原问题虽然没有明说,但我推测问题背景应该是波特图之类的问题,具体问题如下:
对这个函数的幅角求导,代入一个数值为什么求出了个复数值啊,实函数求导应该是实数啊。声明了一下x是实数后好像也不行。
1
2
3
4
5 f[x_] := Arg[(-(x - 1)^2 + 4 (4 x^3 - 3 x^2 - x^4))/((x - 1)^2 + 4 (4 x^3 - 3 x^2 - x^4) - 4*I*(x^3 - 3 x^2 + 2 x))]
f'[5]
(*Out: (513125/13791752+(342351 I)/3447938) Arg'[2499/2626-(765 I)/2626]*)
N[(513125/13791752+(342351 I)/3447938) Arg'[2499/2626-(765 I)/2626]]
(*Out: 0.0109427 + 0.0292034 I*)这是程序,我觉得可能是程序表达的问题,那么该怎么去写这个程序呢?新手上路,老哥请指点
这段程序恰好碰到了Mathematica在求导问题上的两个坑:
- Mathematica总是假设链式求导法则是有效的,但这里遇到的
Arg
本身是一个不可导的函数,链导法则是不成立的。这一点是一个非常常见的坑。 - 然后Mathematica的数值导数设计的也欠合理,在遇到符号求导失效的情况时,Mathematica在计算函数导数时会利用其沿着实轴方向的变化率来近似求导(事实上
Arg
沿复平面不同方向的变化率通常不相等),而Arg
本身总是实数,这样一来得到的Arg'[...]
的结果就总是一个实数,然而前面根据链导法则乘出的那一坨又是个复数,自然得到的最终结果也是复数。
针对这个问题,可以提出两种解决办法:
- 一个很自然的想法是直接绕开
Arg
这个不可导的函数,即可以将通过ComplexExpand
其转化为ArcTan
形式,再去求导就不会有这些问题了:1
2
3f[x_]=ComplexExpand[Arg[(-(x-1)^2+4 (4 x^3-3 x^2-x^4))/((x-1)^2+4 (4 x^3-3 x^2-x^4)-4*I*(x^3-3 x^2+2 x))],TargetFunctions->{Re,Im}];
f'[5]
(*Out: 1117/10504*) - 还可以反过来利用上述数值导数的坑来解决:因为这里就是要求
f
沿实轴方向的导数,所以我们不妨利用数值导数始终沿实轴发生这一特性,先从f
上就避免符号计算引入错误的链导法则,然后直接让Mathematica对f
进行数值求导,于是可以这么写:如果只需要近似的数值值得话,同样可以解决问题。1
2
3
4Clear[f]
f[x_?NumericQ]:=Arg[(-(x-1)^2+4 (4 x^3-3 x^2-x^4))/((x-1)^2+4 (4 x^3-3 x^2-x^4)-4*I*(x^3-3 x^2+2 x))]
f'[5.]
(*Out: 0.10634*)
相关链接: