由于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)
- 使用函数
interp1(),通过线性插值从x0 和y0 计算出与x 的成员相对应的值向量:
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) 并重复。否则绘制(x,y)。
因为abs(x)本质上是一对直线,如果x0包含零,那么线性插值将始终与其对应的计算值完全匹配,err将完全为零,因此上述算法将在最后终止的第一次迭代。如果 x 不包含零,那么 plot(x,y) 将在一组不包括函数“尖点”的点上被调用,并且会发生奇怪的行为。
如果限制在零的任一侧等距且 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 包含零,仅对于每第二个偶数 n。这就是为什么它在 n=6 时正确绘制的原因,因为对于该值 n/2 + 1 = 4,所以 x0 不包含零。对于 n=10、14、18 等也是如此。
选择稍微不对称的限制也可以解决问题,试试:fplot(@abs, [-1.1, 1.2])