Answers:
好问题。R. Baltensperger发表了一篇题为“提高任意搭配点的矩阵微分方法的精度”的论文。这是在我看来,没有什么大不了的,但它有一个点(即已经在2000年出现之前已知的):它强调的事实,准确地表述的重要性,该常数函数的导数应为零(在数学意义上完全成立,但在数字表示中不一定成立)。
显而易见,这要求第n个导数矩阵的行总和为零。通常通过调整对角线条目来强制执行此约束,即通过设置显然,由于浮点计算中的舍入误差,此功能在计算机上工作时并不完全正确。更令人惊讶的是,当对导数矩阵使用解析公式时,这些错误甚至更加严重(可用于许多经典的搭配点,例如高斯-洛巴托)。
现在,论文(及其中的参考文献)指出,导数的误差约为行总和与零的偏差。因此,目标是使这些数值尽可能小。
好的一点是,Fornberg程序在这方面似乎非常好。在下面的图片中,我比较了精确的(即解析的)一阶导数矩阵和由Fornberg算法推导的矩阵的行为,针对不同数量的Chebyshev-Lobatto搭配点。
再次,相信所引用论文中的陈述,这意味着Fornberg算法将对导数产生更准确的结果。
为了证明这一点,我将使用与论文中相同的函数
并评估错误这是针对(i)解析获得的导数矩阵,(ii)Fornberg导数矩阵和(iii)Fornberg矩阵的调整版本而完成的,其中上式为 (1)通过这是我得到的(再次以高斯-洛巴托横坐标为例):
总之,Fornberg的方法似乎非常准确,在的情况下,其准确度甚至比分析公式的结果高3个数量级。对于大多数应用来说,这应该足够准确。而且,这很了不起,因为Fornberg似乎没有在他的方法中明确包含这个事实(至少在Fornberg的两篇论文中没有提及)。
通过直接包含公式(4),可以为该示例获得另一个数量级。由于这是一种非常简单的方法,并且对于每个导数仅应用一次,因此我认为没有理由不使用它。
Baltensperger论文中的方法-使用更复杂的方法来评估等式(1)中的总和以减少舍入误差-产生的误差量级大致相同。因此,至少在此示例中,它大致等同于上面的“ Adjusted Fornberg”方法。
假设您要尝试区分连续函数的数值实现,有很多方法:
1)自动区分。最准确,最通用的方法。对代码很痛苦,需要运算符重载和依赖于参数的查找。给用户增加了理解这些概念的负担。还难以解决可移动的奇点,例如在区分正弦。
2)Chebyshev变换。将函数投影到Chebyshev多项式的范围上,并区分三个项的递归。超快速,非常准确。但要求您有一个紧密支持的兴趣领域;在所选域,这三项复发是不稳定的。
3)有限差分。在1D中被低估;请参阅Nick Higham的数值计算技巧和窍门。这样的想法是,如果您平衡了截断误差和舍入误差,则无需选择步长;可以自动选择。在Boost中,此想法用于(默认情况下)恢复该类型的正确数字的6/7。(Higham仅显示了更简单的情况,即1/2个正确数字的想法,但是这个想法很容易扩展。)系数来自Fornberg的等距表,但是在假定函数可以被评估为1ULP的前提下选择了步长大小。准确性。缺点是需要2次函数求值才能恢复该类型的一半数字,需要4次求出3/4位的数字,依此类推。在1D模式中,这不是一个坏问题。在更高的维度上,这是灾难性的。
4)复步导数。使用。以为单位四舍五入,这几乎可以恢复所有正确的位。但是,这有点作弊,因为通常很难在复杂平面中实现功能,而不是手工编写其真正的导数。还是一个很酷的主意,在某些情况下很有用。
我不知道有人改进了Fornberg的算法(另请参见他的最新论文)。顺便说一句,在我看来,将他的算法视为一种计算数值导数的方法并不正确。他所做的全部工作就是推导一种有效的算法来计算有限差分法的权重。他的方法的优势在于,它可以一口气为您提供所有衍生产品的权重,直至所需的衍生产品。
除了我的其他答案(更多是关于Fornberg方法的扩展)之外,我还将在这里解决更简单的替代方法的问题。
为此,我绘制了一个替代方案,该方案可以更直接地产生拉格朗日插值的导数系数。它的实现只需要几行代码,就可以在任意网格上工作,并且根据我的第一个实验,它和Fornberg一样准确。
实现的基础是虚步导数
其中是机器精度顺序的变量。已知虚步导数可稳定地生成导数值,并且不会遭受的有限差分实现的数值不稳定性。
第二个成分是使用重心形式之一评估的网格上的Lagrange插值多项式,例如
,其中
为了使用复数步导数,必须确保这些公式也适用于复数参数。此外,对于给定的函数f(x)和系数矢量,我们表示通过插补多项式由
下面概述了该算法。它具有与Fornberg相同的输入和输出参数,但是更容易理解。
输入:
初始化
算法
而:
计算
通过复步骤衍生物为和全部。
在此,表示第行。
设置o = o + 1;
决定输出什么:
有限差分系数的矢量在点,其中。这就是Fornberg所做的。
插值函数到导数订单。为此,您必须输入一个功能代表。函数处的函数值对算法。
一个元函数返回变量2的插值函数,但是对于要在网格点处插值的任意函数。
我个人最喜欢变体3。
与Fornberg一样,此算法为。如果有时间的话,我将发布有关准确性,稳定性等方面的更多经验性结果。
要提高数值微分的精度,请执行以下操作:
1)根据一些步长h选择您最喜欢的高精度“标准”方法。
2)用1)中选择的方法,以不同但合理的步长h多次计算导数的值。每次您都可以从间隔(0.5 * H / 10,1.5 * H / 10)中选择h作为随机数,其中H是所用方法的合适步长。
3)平均结果。
您的结果的绝对误差wrt可能会增加2-3个数量级。非平均结果。