0
点赞
收藏
分享

微信扫一扫

导数的定义(哎,忘光了)

天悦哥 2022-05-01 阅读 182

1.定义

导数就是表示某个瞬间的变化量。它可以定义成下面的式子。

在这里插入图片描述

式(4.4)表示的是函数的导数。左边的符号 d f ( x ) d x \frac{{\rm d}f(x)}{{\rm d}x} dxdf(x)
表示 f (x )关于 x 的导数,即 f (x )相对于 x 的变化程度。式(4.4)表示的导数的含义是,x 的“微小变化”将导致函数 f (x )的值在多大程度上发生变化。其中,表示微小变化的 h 无限趋近 0,表示为 : lim ⁡ h → 0 \lim_{h\to0} h0lim

2.代码实现

不好的示例

def numerical_diff(f, x):
    h = 1e-50
    return (f(x + h) - f(x)) / h

函数 numerical_diff(f, x) 的名称来源于数值微分 1 的英文 numerical differentiation。这个函数有两个参数,即“函数 f ”和“传给函数 f 的参数 x ”。乍一看这个实现没有问题,但是实际上这段代码有两处需要改进的地方。

在上面的实现中,因为想把尽可能小的值赋给 h (可以话,想让 h 无限接近 0),所以 h 使用了 10e-50 (有 50 个连续的 0 的“0.00 … 1”)这个微小值。但是,这样反而产生了舍入误差 (rounding error)。所谓舍入误差,是指因省略小数的精细部分的数值(比如,小数点第 8 位以后的数值)而造成最终的计算结果上的误差。比如,在 Python 中,舍入误差可如下表示。

print(np.float(1e-50))

运行结果:

1e-50

如上所示,如果用 float32 类型(32 位的浮点数)来表示 1e-50 ,就会变成 0.0,无法正确表示出来。也就是说,使用过小的值会造成计算机出现计算上的问题。这是第一个需要改进的地方,即将微小值 h 改为 10-4 。使用 10-4 就可以得到正确的结果。(这个可以看下面示例代码的运行结果)

第二个需要改进的地方与函数 f 的差分有关。虽然上述实现中计算了函数 f 在 x+h 和 x 之间的差分,但是必须注意到,这个计算从一开始就有误差。如下图 所示,“真的导数”对应函数在 x 处的斜率(称为切线),但上述实现中计算的导数对应的是 (x + h ) 和 x 之间的斜率。因此,真的导数(真的切线)和上述实现中得到的导数的值在严格意义上并不一致。这个差异的出现是因为 h 不可能无限接近 0。

如下图 所示,数值微分含有误差。为了减小这个误差,我们可以计算函数 f 在 (x + h ) 和 (x - h ) 之间的差分。因为这种计算方法以 x 为中心,计算它左右两边的差分,所以也称为中心差分 (而 (x + h ) 和 x 之间的差分称为前向差分 )。下面,我们基于上述两个要改进的点来实现数值微分(数值梯度)。
在这里插入图片描述
对比示例1:

import numpy as np


def numerical_diff(f, x):
    h = 1e-50
    return (f(x + h) - f(x - h)) / (2 * h)


def f(x):
    return x ** 2


if __name__ == '__main__':
    print(numerical_diff(f, 2))

运行结果:

0.0

对比示例2:

import numpy as np


def numerical_diff(f, x):
    h = 1e-4
    return (f(x + h) - f(x - h)) / (2 * h)


def f(x):
    return x ** 2


if __name__ == '__main__':
    print(numerical_diff(f, 2))

运行结果:

4.000000000004

如上所示,利用微小的差分求导数的过程称为数值微分 (numerical differentiation)。

而基于数学式的推导求导数的过程,则用“解析性 ”(analytic)一词,称为“解析性求解”或者“解析性求导”。比如,y = x^2 的导数,可以通过 d y d x = 2 x \frac{{\rm d} y}{{\rm d} x}=2x dxdy=2x 解析性地求解出来。因此,当 x = 2 时,y 的导数为 4。解析性求导得到的导数是不含误差的“真的导数”。

举报

相关推荐

0 条评论