【发布时间】:2009-03-09 16:49:09
【问题描述】:
我正在寻找一种使用离散且快速的方法来计算导数的方法。由于现在我不知道我所拥有的方程的类型,因此我正在寻找类似于我们可以找到的积分方法的离散方法,例如欧拉方法。
【问题讨论】:
标签: discrete-mathematics derivative
我正在寻找一种使用离散且快速的方法来计算导数的方法。由于现在我不知道我所拥有的方程的类型,因此我正在寻找类似于我们可以找到的积分方法的离散方法,例如欧拉方法。
【问题讨论】:
标签: discrete-mathematics derivative
我认为您正在寻找以点计算的导数。 如果是这种情况,这里有一个简单的方法可以做到这一点。你需要知道一点的导数,比如a。它由 h->0 的差商的极限给出:
您实际上需要实现限制功能。所以你:
现在处于 DO-WHILE 循环中:
1- 将 h 除以 2(或除以 10,重要的是使其更小)
2- 用新的 h 值再次计算差商,将其存储在 f2
3- 设置 diff = abs(f2-f1)
4- 分配 f1 = f2
5- 从第 1 点重复 while (diff>epsilon)
记住: 您假设函数在 a 中是可微的。 由于您的计算机可以处理的有限十进制数字的错误,您将得到的每个结果都是错误的,这是无法逃脱的。
python中的示例:
def derive(f, a, h=0.01, epsilon = 1e-7):
f1 = (f(a+h)-f(a))/h
while True: # DO-WHILE
h /= 2.
f2 = (f(a+h)-f(a))/h
diff = abs(f2-f1)
f1 = f2
if diff<epsilon: break
return f2
print "derivatives in x=0"
print "x^2: \t\t %.6f" % derive(lambda x: x**2,0)
print "x:\t\t %.6f" % derive(lambda x: x,0)
print "(x-1)^2:\t %.6f" % derive(lambda x: (x-1)**2,0)
print "\n\nReal values:"
print derive(lambda x: x**2,0)
print derive(lambda x: x,0)
print derive(lambda x: (x-1)**2,0)
输出:
derivatives in x=0
x^2: 0.000000
x: 1.000000
(x-1)^2: -2.000000
Real values:
7.62939453125e-08
1.0
-1.99999992328
我第一次得到“精确”值“因为只使用了结果的前 6 位数字,请注意我使用 1e-7 作为 epsilon。之后打印 REAL 计算值,它们显然是数学上的错误。选择多小的 epsilon 取决于您希望结果有多精确。
【讨论】:
在计算数值(“有限”)导数方面有相当多的理论(和既定实践)。让所有细节正确,让您相信结果,这并非易事。如果有任何方法可以获得函数的解析导数(使用笔和纸,或计算机代数系统,例如 Maple、Mathematica、Sage 或 SymPy),这是迄今为止最好的选项。
如果你不能得到解析形式,或者你不知道函数(只是它的输出),那么数值估计是你唯一的选择。这个chapter in Numerical Recipies in C 是一个好的开始。
【讨论】:
一种简单的方法是针对您感兴趣的导数的每个点计算 f 在一个小值上的变化。例如,要计算 ∂f/∂x,您可以使用以下方法:
epsilon = 1e-8
∂f/∂x(x, y, z) = (f(x+epsilon,y,z) - f(x-epsilon, y, z))/(epsilon * 2);
其他部分在 y 和 z 中是相似的。
为 epsilon 选择的值取决于 f 的内容、所需的精度、使用的浮点类型以及可能的其他因素。我建议你用你感兴趣的函数来试验它的值。
【讨论】:
要进行数值微分,这始终是一个近似值,有两种常见的情况:
* Andrea 的答案使用前向差分算子 {f(a+h) - f(a)}/h 而不是中心差分算子 {f(a+h) - f(a-h)}/2h,但前向差分算子在数值解中精度较低。
【讨论】:
不使用像 Maple 这样的符号数学语言,您能做的最好的事情就是在各个点近似导数。 (然后插值,如果你需要一个函数。)
如果你已经有了想要使用的功能,那么你应该使用backward divided-difference forumla和Richardson extrapolation来改善你的错误。
还要记住,这些方法适用于一个变量的函数。但是,每个变量的偏导数将其他变量视为常数。
【讨论】:
Automatic differentiation 是做这种事情的最准确和概念上最棒的方式。稍微复杂一点。
【讨论】:
正式地说,不。您正在描述离散函数的(偏)导数,或者您正在寻求一种数值方法来逼近连续函数的(偏)导数。
离散函数没有导数。如果您查看导数的 epsilon-delta 定义,您会发现您需要能够在接近您想要导数的点处评估函数。如果函数的值只有 x、y 和 z 的整数值,这没有任何意义。所以没有办法找到一个离散函数对任何fast值的导数。
如果您想要一种数值方法来精确计算连续函数的导数,那么您也很不走运。导数的数值方法是启发式的,而不是算法的。没有数值方法可以保证精确解。幸运的是,存在许多好的启发式方法。 Mathematica 默认使用 Brent's principle axis method 的专用版本。我建议你使用GNU Scientific Library,它很好地实现了布伦特的方法。我的一门数学课程的全部成绩都归功于 GSL。如果这是你的事,红宝石绑定非常好。如有必要,大多数数值微分库都有一些可用的不同方法。
如果你真的想要,我可以拿出一些示例代码。告诉我。
【讨论】:
我假设您的函数比您发布的简单函数更复杂,因为封闭式解决方案太简单了。
当您使用“离散”一词时,我认为您需要“有限差异”。您需要一些离散化来计算近似值。
Df/Dx ~ (f2-f1)/(x2-x1)等
【讨论】:
我希望这可能会有所帮助NUMERICAL DIFFERENTIATION.
【讨论】:
如果函数如您所指出的那样是线性的,那么导数是微不足道的。关于“x”的导数是“a”;关于“y”的导数是“b”,关于“z”的导数是“c”。如果方程是更复杂的形式,并且您需要一个表示解的公式而不是经验解,那么请提交更复杂的方程形式。
问候
【讨论】: