Octave fplot abs 看起来很奇怪
Octave fplot abs looks very strange
f = @(x)(abs(x))
fplot(f, [-1, 1]
全新安装的 Octave,未编辑任何配置。它产生了下图,它看起来好像在 0 附近有一段时间是恒定的,看起来更像 \_/ 而不是 \/:
为什么它看起来与通常的绝对值接近 0 的图如此不同?如何解决?
文档说:“fplot 最适合连续函数。具有不连续性的函数不太可能很好地绘制。将来可能会删除此限制。”所以它可能是函数本身的一个bug/feature,只有开发人员才能修复。普通的 plot()
函数工作正常:
x = [-1 0 1];
y = abs(x);
plot(x, y);
奇怪的形状来自采样率,即在多少点评估函数。这是由 fplot
的参数 N
控制的 默认调用似乎不小心跳过了 x=0,并且使用 fplot(@abs, [-1, 1], N=5)
我得到了和你一样有趣的形状:
但是,尝试 N
的不同值可以产生正确的形状,例如尝试fplot(@abs, [-1, 1], N=6)
:
虽然一般来说我会建议使用更高的数字,比如 N=100
。
由于fplot
是用Octave写的,所以相对容易阅读。可以使用 which
命令找到它的位置。在我的系统上,这给出了:
octave:1> which fplot
'fplot' is a function from the file /usr/share/octave/5.2.0/m/plot/draw/fplot.m
检查 fplot.m
表明要绘制的函数 f(x) 在给定限制之间的 n 个等距点处进行计算。确定n的算法从第192行开始,可以总结如下:
- n 最初选择为 8(除非用户另有指定)
- 使用 n/2 + 1 点的较粗网格构建参数向量:
x0 = linspace (limits(1), limits(2), n/2 + 1)'
(linspace 函数将接受一个非整数值作为点数,它向下舍入)
- 计算相应的值:
y0 = f(x0)
- 使用 n 个点的网格构造参数向量:
x = linspace (limits(1), limits(2), n)'
- 计算相应的值:
y = f(x0)
- 构造一个向量,其值对应于 x 的成员,但使用函数
interp1()
通过线性插值从 x0 和 y0 计算得出:
yi = interp1 (x0, y0, x, "linear")
- 使用以下公式计算错误度量:
err = 0.5 * max (abs ((yi - y) ./ (yi + y + eps))(:))
也就是说,err
与计算值和线性插值之间的最大差值成正比。
- 如果
err
大于 tol
(2e-3,除非用户指定)然后输入 n = 2*(n-1) 并重复。否则 plot(x,y).
因为 abs(x)
本质上是一对直线,如果 x0 包含零,那么线性插值将始终与它们对应的计算值完全匹配,而 err
将恰好为零,所以上面算法将在第一次迭代结束时终止。如果 x 不包含零,那么 plot(x,y)
将在一组不包括函数 'cusp' 的点上调用,并且会出现奇怪的行为。
如果限制在零的任一侧等距且 floor(n/2 + 1) 为奇数,默认值 (limits = [-5, 5], n = 8).
可以通过选择 n
和 limits
的组合来避免出现以下情况之一:
a) m = floor(n/2 + 1) 等距点的集合不包括零或
b) n 个等距点的集合确实包含零。
例如,在零和奇数 n 的任一侧等间距的极限将正确绘制。不过,这对 n=5 不起作用,因为奇怪的是,如果用户输入 n=5,fplot.m
会用 8 代替它(我不确定为什么这样做,我认为这可能是一个错误).所以 fplot(@abs, [-1, 1], 3)
和 fplot(@abs, [-1, 1], 7)
会正确绘制,但 fplot(@abs, [-1, 1], 5)
不会。
(n/2 + 1) 是奇数,因此 x0 包含对称极限的零,仅对于每个第 2 个偶数 n。这就是它使用 n=6 正确绘制的原因,因为对于该值 n/2 + 1 = 4,所以 x0 不包含零。 n=10、14、18等也是如此。
选择稍微不对称的限制也可以,试试:fplot(@abs, [-1.1, 1.2])
f = @(x)(abs(x))
fplot(f, [-1, 1]
全新安装的 Octave,未编辑任何配置。它产生了下图,它看起来好像在 0 附近有一段时间是恒定的,看起来更像 \_/ 而不是 \/:
为什么它看起来与通常的绝对值接近 0 的图如此不同?如何解决?
文档说:“fplot 最适合连续函数。具有不连续性的函数不太可能很好地绘制。将来可能会删除此限制。”所以它可能是函数本身的一个bug/feature,只有开发人员才能修复。普通的 plot()
函数工作正常:
x = [-1 0 1];
y = abs(x);
plot(x, y);
奇怪的形状来自采样率,即在多少点评估函数。这是由 fplot
的参数 N
控制的 默认调用似乎不小心跳过了 x=0,并且使用 fplot(@abs, [-1, 1], N=5)
我得到了和你一样有趣的形状:
但是,尝试 N
的不同值可以产生正确的形状,例如尝试fplot(@abs, [-1, 1], N=6)
:
虽然一般来说我会建议使用更高的数字,比如 N=100
。
由于fplot
是用Octave写的,所以相对容易阅读。可以使用 which
命令找到它的位置。在我的系统上,这给出了:
octave:1> which fplot
'fplot' is a function from the file /usr/share/octave/5.2.0/m/plot/draw/fplot.m
检查 fplot.m
表明要绘制的函数 f(x) 在给定限制之间的 n 个等距点处进行计算。确定n的算法从第192行开始,可以总结如下:
- n 最初选择为 8(除非用户另有指定)
- 使用 n/2 + 1 点的较粗网格构建参数向量:
x0 = linspace (limits(1), limits(2), n/2 + 1)'
(linspace 函数将接受一个非整数值作为点数,它向下舍入) - 计算相应的值:
y0 = f(x0)
- 使用 n 个点的网格构造参数向量:
x = linspace (limits(1), limits(2), n)'
- 计算相应的值:
y = f(x0)
- 构造一个向量,其值对应于 x 的成员,但使用函数
interp1()
通过线性插值从 x0 和 y0 计算得出:yi = interp1 (x0, y0, x, "linear")
- 使用以下公式计算错误度量:
err = 0.5 * max (abs ((yi - y) ./ (yi + y + eps))(:))
也就是说,err
与计算值和线性插值之间的最大差值成正比。 - 如果
err
大于tol
(2e-3,除非用户指定)然后输入 n = 2*(n-1) 并重复。否则 plot(x,y).
因为 abs(x)
本质上是一对直线,如果 x0 包含零,那么线性插值将始终与它们对应的计算值完全匹配,而 err
将恰好为零,所以上面算法将在第一次迭代结束时终止。如果 x 不包含零,那么 plot(x,y)
将在一组不包括函数 'cusp' 的点上调用,并且会出现奇怪的行为。
如果限制在零的任一侧等距且 floor(n/2 + 1) 为奇数,默认值 (limits = [-5, 5], n = 8).
可以通过选择 n
和 limits
的组合来避免出现以下情况之一:
a) m = floor(n/2 + 1) 等距点的集合不包括零或
b) n 个等距点的集合确实包含零。
例如,在零和奇数 n 的任一侧等间距的极限将正确绘制。不过,这对 n=5 不起作用,因为奇怪的是,如果用户输入 n=5,fplot.m
会用 8 代替它(我不确定为什么这样做,我认为这可能是一个错误).所以 fplot(@abs, [-1, 1], 3)
和 fplot(@abs, [-1, 1], 7)
会正确绘制,但 fplot(@abs, [-1, 1], 5)
不会。
(n/2 + 1) 是奇数,因此 x0 包含对称极限的零,仅对于每个第 2 个偶数 n。这就是它使用 n=6 正确绘制的原因,因为对于该值 n/2 + 1 = 4,所以 x0 不包含零。 n=10、14、18等也是如此。
选择稍微不对称的限制也可以,试试:fplot(@abs, [-1.1, 1.2])