使用离散方法计算导数

时间:2009-03-09 16:49:09

标签: discrete-mathematics derivative

我正在寻找一种使用离散和快速方法计算导数的方法。由于现在我不知道我所拥有的等式的类型,我正在寻找类似于我们可以为积分找到的离散方法,例如欧拉方法。

10 个答案:

答案 0 :(得分:10)

我认为你正在寻找一个点计算的导数。 如果是这种情况,这里有一个简单的方法。你需要知道某一点的导数,比如 a 。它由h-> 0的差商的极限给出:

difference quotient

您实际上需要实现限制功能。所以你:

  • 定义一个epsilon,将其设置得更小,更精确,更大,更快
  • 计算起始h中的差商,假设h = 0.01,将其存储在 f1
  • 现在处于DO-WHILE循环中:

    1-将h除以2(或10,重要的是使其变小)
    2-再次计算与h的新值的差商,将其存储在 f2
    中 3-设置 diff = abs(f2-f1)
    4-指定 f1 = f2
    从第1点开始重复而(diff> epsilon)

  • 您最终可以将f1(或f2)作为f'(a)
  • 的值返回

记住: 您假设该功能在 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计算值,它们显然是数学上的选择小ε是多么取决于你想要的结果精确程度。

答案 1 :(得分:7)

在计算数值(“有限”)导数时,有相当多的理论(和惯例)。获得所有细节是正确的,这样您相信结果并非易事。如果有任何方法可以获得函数的分析导数(使用笔和纸,或计算机代数系统,如MapleMathematicaSageSymPy ),这是迄今为止最好的选择。

如果您无法获得分析表格,或者您不知道该功能(只是它的输出),那么数值估算是您唯一的选择。 C中的数字Recipies中的这个chapter是一个好的开始。

答案 2 :(得分:4)

一个简单的方法是计算你感兴趣的导数的每个点的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的内容,所需的精度,使用的浮点类型以及可能的其他内容。我建议你用你感兴趣的函数来试验它的值。

答案 3 :(得分:3)

要进行数值微分,这总是近似值,有两种常见的情况:

  1. 你有一种方法(算法,方程式)来计算任何给定x的f(x)的值,或
  2. 在一组等间隔的x(f(1),f(1.5),f(2)等)中有f(x)的值:


  1. 如果你有算法,那么你最好看Andrea Ambu's answer *:
    1. 从f(a + h)和f(a-h)的值开始,然后执行
      f'(a)= {f(a + h)-f(a-h)} / 2h
      这被称为中心差异。
    2. 根据Andrea的回答,缩小偏移量h的大小,直到f'(a)停止变化。
    • 小心不要在没有检查大于0的情况下除以2h,否则你会得到除以零的错误。
  2. 如果你在一组f(x)= f(x n )= f n 的值中得到函数的值,那么我们可以做点什么类似于上面的方法,但我们的准确性将受到x n 的值以及它们之间的间隙的限制。
  3. 第一个近似就是使用与上述相同的中心差分算子;
    f' n =(f n + 1 - f n-1 )/ 2h,
    其中h是x n 的值之间的相等间距。
  4. 接下来是使用five-point stencil,虽然它只有维基百科页面上详细列出的4个系数。这使用从f n-2 到f n + 2 的值:f' n =( - f n + 2 < / sub> + 8f n + 1 - 8f n-1 + f n-2 )/ 12h。
  5. 使用更多的点有更高阶近似值,但它们越来越难以计算收益递减,并且在数值上变得更不稳定。
  6. **注意**:这些有限差分公式依赖于f与x n-1 ≤x≤ n + 1 ≤x≤ n + 1 ≤x≤ n + 1 中的多项式大致相同的形状。对于像正弦波这样的函数,它们在计算导数时可能非常糟糕。
  7. * Andrea的答案使用前向差分算子{f(a + h) - f(a)} / h而不是中心差分算子{f(a + h) - f(ah)} / 2h,但是前向差分算子在数值解中不太准确。

答案 4 :(得分:2)

如果不使用像Maple这样的符号数学语言,你可以做的最好的事情就是在不同的点上逼近导数。 (然后插入,如果你需要一个函数。)

如果您已经拥有了要使用的功能,那么您应该使用backward divided-difference forumlaRichardson extrapolation来改善错误。

另请注意,这些方法适用于一个变量的功能。但是,每个变量的偏导数将其他变量视为常数。

答案 5 :(得分:2)

Automatic differentiation是做这种事情最准确,最概念性的方式。只是有点复杂。

答案 6 :(得分:1)

正式,不。你要么描述离散函数的(部分)导数,要么就是要求一种数值方法来逼近连续函数的(部分)导数。

离散函数没有导数。如果您查看导数的epsilon-delta定义,您将看到需要能够在接近您想要导数的点处评估函数。如果函数仅具有x,y和z的整数值的值,则没有意义。所以没有办法找到任何快速值的离散函数的导数。

如果你想要一个数值方法精确计算连续函数的导数,那么你运气也不好。导数的数值方法是启发式的,而不是算法的。没有数值方法可以保证精确的解决方案。幸运的是,存在许多良好的启发式方法。 Mathematica默认使用Brent's principle axis method的专用版本。我建议你使用GNU Scientific Library,它有很好的Brent方法实现。我将自己的全部成绩归功于我的一门数学课程。如果那是你的东西,ruby绑定非常好。如有必要,大多数数值微分库都有一些不同的方法可用。

如果你真的想要,我可以提供一些示例代码。让我知道。

答案 7 :(得分:0)

我认为你的功能比你发布的简单功能更复杂,因为封闭形式的解决方案太简单了。

当你使用“离散”这个词时,我认为你需要“有限差异”。您需要一些离散化来计算近似值。

Df / Dx~(f2-f1)/(x2-x1)等

答案 8 :(得分:0)

我希望这可能会有所帮助NUMERICAL DIFFERENTIATION.

答案 9 :(得分:-1)

如果函数是线性的,则表明衍生物是微不足道的。关于'x'的导数是'a';关于'y'的导数是'b',关于'z'的导数是'c'。如果方程是一个更复杂的形式,你需要一个代表解决方案而不是经验解的公式,那么请提交更复杂的方程式。

此致