Julia 如何表示二阶数值微分的截断误差是一阶数值微分的平方

Julia 如何表示二阶数值微分的截断误差是一阶数值微分的平方,julia,numeric,numerical-analysis,numerical-computing,Julia,Numeric,Numerical Analysis,Numerical Computing,我试图证明二阶数值微分的截断误差确实给了我们比一阶数值微分的两倍精度(考虑到机器误差/舍入误差eps()) 以下是我在Julia中的代码: function first_order_numerical_D(f) function df(x) h = sqrt(eps(x)) (f(x+h) - f(x))/h end df end function second_order_numerical_D(f) function df(x) h

我试图证明二阶数值微分的截断误差确实给了我们比一阶数值微分的两倍精度(考虑到机器误差/舍入误差
eps()

以下是我在Julia中的代码:

function first_order_numerical_D(f)
  function df(x)
    h = sqrt(eps(x))        
    (f(x+h) - f(x))/h
  end
  df
end

function second_order_numerical_D(f)
  function df(x)
    h = sqrt(eps(x))          
    (f(x+h) - f(x-h))/(2.0*h)
  end
  df
end

function analytical_diff_exp(x)
    return exp(x)
end
function analytical_diff_sin(x)
    return cos(x)
end
function analytical_diff_cos(x)
    return -sin(x)
end
function analytical_diff_sqrt(x)
    return 1/(2.0*sqrt(x))
end

function first_order_error_exp(x)
    return first_order_numerical_D(exp)(x) - analytical_diff_exp(x) 
end
function first_order_error_sin(x)
    return first_order_numerical_D(sin)(x) - analytical_diff_sin(x) 
end
function first_order_error_cos(x)
    return first_order_numerical_D(cos)(x) - analytical_diff_cos(x) 
end
function first_order_error_sqrt(x)
    return first_order_numerical_D(sqrt)(x) - analytical_diff_sqrt(x) 
end

function second_order_error_exp(x)
    return second_order_numerical_D(exp)(x) - analytical_diff_exp(x)
end
function second_order_error_sin(x)
    return second_order_numerical_D(sin)(x) - analytical_diff_sin(x)
end
function second_order_error_cos(x)
    return second_order_numerical_D(cos)(x) - analytical_diff_cos(x) 
end
function second_order_error_sqrt(x)
    return second_order_numerical_D(sqrt)(x) - analytical_diff_sqrt(x) 
end

function round_off_err_exp(x)
    return 2.0*sqrt(eps(x))*exp(x)
end
function round_off_err_sin(x)
    return 2.0*sqrt(eps(x))*sin(x)
end
function round_off_err_cos(x)
    return 2.0*sqrt(eps(x))*cos(x)
end
function round_off_err_sqrt(x)
    return 2.0*sqrt(eps(x))*sqrt(x)
end

function first_order_truncation_err_exp(x)
    return abs(first_order_error_exp(x)+round_off_err_exp(x))
end
function first_order_truncation_err_sin(x)
    return abs(first_order_error_sin(x)+round_off_err_sin(x))
end
function first_order_truncation_err_cos(x)
    return abs(first_order_error_cos(x)+round_off_err_cos(x))
end
function first_order_truncation_err_sqrt(x)
    return abs(first_order_error_sqrt(x)+round_off_err_sqrt(x))
end

function second_order_truncation_err_exp(x)
    return abs(second_order_error_exp(x)+0.5*round_off_err_exp(x))
end
function second_order_truncation_err_sin(x)
    return abs(second_order_error_sin(x)+0.5*round_off_err_sin(x))
end
function second_order_truncation_err_cos(x)
    return abs(second_order_error_cos(x)+0.5*round_off_err_cos(x))
end
function second_order_truncation_err_sqrt(x)
    return abs(second_order_error_sqrt(x)+0.5*round_off_err_sqrt(x))
end
如果我减去
round\u off\u err\f
项(这里我使用add,因为实际的泰勒展开显示舍入误差和截断误差前面都有负号),这应该会给出正确的截断误差

有关分析推导/证明,请参见:

但结果表明:

first_order_truncation_err_exp(0.5), first_order_truncation_err_sin(0.5), first_order_truncation_err_cos(0.5), first_order_truncation_err_sqrt(0.5)

(4.6783240139052204e-8, 1.2990419187857229e-8, 2.8342226290287478e-9, 4.364449135429996e-9)

second_order_truncation_err_exp(0.5), second_order_truncation_err_sin(0.5), second_order_truncation_err_cos(0.5), second_order_truncation_err_sqrt(0.5)

(1.8874426561390482e-8, 7.938850300905947e-9, 4.1240999200086055e-9, 7.45058059692383e-9)
其中:

eps(0.5)=1.1102230246251565e-16

second\u order\u truncation\u err\u f()
应该是
1e-16
的顺序,而不是
1e-8
,我不知道这为什么不起作用。

这是因为你的计算主要是由舍入误差控制的。即:

julia> round_off_err_sqrt(0.5)
1.490116119384766e-8
为了看到“二阶”导数之间的差异(通常我会看到术语中心差),你需要选择一个更大的步长。在文献中通常可以看到
h=cbrt(eps())

function second_order_numerical_D(f)
    function df(x)
        h = cbrt(eps(x))          
        (f(x+h/2) - f(x-h/2))/h
    end
    df
end
julia> second_order_error_exp(0.5)
1.308131380994837e-11

请注意,它仍然没有到达
1e-16
。也就是说,由于减法消除错误。您可以通过复步长法或自动微分法避免这种情况,我实际上通过使用
first\u order\u truncation\u err\u f=abs(first\u order\u error\u f(x)+round\u off\u err\u f(x))
将所有舍入误差近似为
rand()*2.0*eps(x)/sqrt(eps(x))
由我在问题中发布的注释衍生而来。这个问题的目的并不是使用自动微分。
一阶误差f(x)+舍入误差f(x)
如果你分别检查这些函数的符号,你会发现它们通常具有相同的符号,因为这里的实际舍入误差实际上是
舍入误差f(x)
,更具体地说,
analytical\u diff\u f(x)-numerical\u diff\u f(x)=-截断\u err\u f(x)-round\u off\u err\u f(x)
so
abs(truncation\u err\u f(x))=abs(analytical\u diff\u f(x)-numerical\u diff\u f(x)+round\u off\u err\u f(x))
如果您想显示缩放比例,我建议您绘制减小步长的误差图,这将很好地显示缩放效果。我怀疑通过有限差分计算您是否能达到1e-16。