尝试在 MATLAB 中实现差异公式
Trying to implement the difference formula in MATLAB
我正在尝试实现差异公式
f'(x) ≈ [ f(x+h) - f(x) ] / h
对 x=1
和 h=10^-k
使用 MATLAB,其中 k=0,...,16
。此外,我想绘制错误。
下面是我的代码。我看到错误在 3 左右,我认为它太大了。它应该接近于 0。
syms f(x)
f(x) = tan(x);
df = diff(f,x);
x = 1;
for k = 0:16
h = 10^-k;
finitediff = double((f(x+h)-f(x))/h);
err = double(abs(finitediff-df(x)));
end
你的代码没有问题,有限差分公式运行良好,你得到的错误在于计算以下数值的项目:
当a
和b
都非常非常小时计算a/b
产生的错误。
计算 a-b
当 a
和 b
非常非常接近时 MATLAB 将给出 0
.
这是k从1变为15时的结果:
感谢@CrisLuengo 富有洞察力的评论!
表明err
瞬间下降到接近于零,当h
变为1e-9
时再次上升(情况1发生在这之后)。当h
变为1e-14
时,最终df
变为0(这里出现情况2)。
我在你的代码中添加了几行代码来展示这一点:
clc;
clear;
format long
syms f(x)
f(x) = tan(x);
h=1;
df = diff(f,x);
double(df(1));
x=1;
range=1:15;
[finitediff,err]=deal(zeros(size(range)));
for k=range
h=10^-k;
finitediff(k)=double((f(x+h)-f(x))/h);
err(k)=double(abs(finitediff(k)-df(1)));
end
figure(1)
subplot(1,2,1)
hold on
plot(err)
plot(err,'bx')
set(gca,'yscale','log')
title('err')
subplot(1,2,2)
hold on
ezplot(df)
axis([0.5 1.5 0 5])
plot(ones(size(range)),finitediff,'rx','MarkerSize',7)
for ii=range
text(1,finitediff(ii),['h=1e-' num2str(ii)])
end
您正在计算 x+h
数值。对于 x=1
,您可以生成的大于 x
的最小数字是 x+eps(x) = 1+eps(1)
。 eps(1)
是 2.2204e-16
。所以添加 h=1e-16
不会改变 x
。现在,您正在象征性地计算 tan(1)-tan(1)
,即 0。因此您对导数的有限差分近似为 0。
但即使 h
较大,您的差异也为 0。我认为这是因为计算切线时出现舍入误差。请注意
x = 1;
h = 1e-14;
f(x+h)
returnstan(1)
。也就是说,符号工具箱认为 tan
函数上下文中的 1+1e-14 足够接近 1 以保证四舍五入。有趣的是,
f(x+h)-f(x)
returns 0,而
tan(x+h)-tan(x)
returns 3.4195e-14
(接近预期的 3.4255e-14
)。
请注意,正如您可以通过 看出的那样,最好的近似值是 h=10^-8
,随着您减少 h
,x+h
中的舍入误差开始减少增加(使用 set(gca,'yscale','log')
来查看)。
我正在尝试实现差异公式
f'(x) ≈ [ f(x+h) - f(x) ] / h
对 x=1
和 h=10^-k
使用 MATLAB,其中 k=0,...,16
。此外,我想绘制错误。
下面是我的代码。我看到错误在 3 左右,我认为它太大了。它应该接近于 0。
syms f(x)
f(x) = tan(x);
df = diff(f,x);
x = 1;
for k = 0:16
h = 10^-k;
finitediff = double((f(x+h)-f(x))/h);
err = double(abs(finitediff-df(x)));
end
你的代码没有问题,有限差分公式运行良好,你得到的错误在于计算以下数值的项目:
当
a
和b
都非常非常小时计算a/b
产生的错误。计算
a-b
当a
和b
非常非常接近时 MATLAB 将给出0
.
这是k从1变为15时的结果:
感谢@CrisLuengo 富有洞察力的评论!
表明err
瞬间下降到接近于零,当h
变为1e-9
时再次上升(情况1发生在这之后)。当h
变为1e-14
时,最终df
变为0(这里出现情况2)。
我在你的代码中添加了几行代码来展示这一点:
clc;
clear;
format long
syms f(x)
f(x) = tan(x);
h=1;
df = diff(f,x);
double(df(1));
x=1;
range=1:15;
[finitediff,err]=deal(zeros(size(range)));
for k=range
h=10^-k;
finitediff(k)=double((f(x+h)-f(x))/h);
err(k)=double(abs(finitediff(k)-df(1)));
end
figure(1)
subplot(1,2,1)
hold on
plot(err)
plot(err,'bx')
set(gca,'yscale','log')
title('err')
subplot(1,2,2)
hold on
ezplot(df)
axis([0.5 1.5 0 5])
plot(ones(size(range)),finitediff,'rx','MarkerSize',7)
for ii=range
text(1,finitediff(ii),['h=1e-' num2str(ii)])
end
您正在计算 x+h
数值。对于 x=1
,您可以生成的大于 x
的最小数字是 x+eps(x) = 1+eps(1)
。 eps(1)
是 2.2204e-16
。所以添加 h=1e-16
不会改变 x
。现在,您正在象征性地计算 tan(1)-tan(1)
,即 0。因此您对导数的有限差分近似为 0。
但即使 h
较大,您的差异也为 0。我认为这是因为计算切线时出现舍入误差。请注意
x = 1;
h = 1e-14;
f(x+h)
returnstan(1)
。也就是说,符号工具箱认为 tan
函数上下文中的 1+1e-14 足够接近 1 以保证四舍五入。有趣的是,
f(x+h)-f(x)
returns 0,而
tan(x+h)-tan(x)
returns 3.4195e-14
(接近预期的 3.4255e-14
)。
请注意,正如您可以通过 h=10^-8
,随着您减少 h
,x+h
中的舍入误差开始减少增加(使用 set(gca,'yscale','log')
来查看)。