Reputation: 121
f = @(x)(abs(x))
fplot(f, [-1, 1]
Freshly installed octave, with no configuration edited. It results in the following image, where it looks as if it is constant for a while around 0, looking more like a \_/ than a \/:
Why does it look so different from a usual plot of the absolute value near 0? How can this be fixed?
Upvotes: 0
Views: 149
Reputation: 926
Since fplot
is written in Octave it is relatively easy to read. Its location can be found using the which
command. On my system this gives:
octave:1> which fplot
'fplot' is a function from the file /usr/share/octave/5.2.0/m/plot/draw/fplot.m
Examining fplot.m
reveals that the function to be plotted, f(x), is evaluated at n equally spaced points between the given limits. The algorithm for determining n starts at line 192 and can be summarised as follows:
x0 = linspace (limits(1), limits(2), n/2 + 1)'
(The linspace function will accept a non-integer value for the number of points, which it rounds down)y0 = f(x0)
x = linspace (limits(1), limits(2), n)'
y = f(x0)
interp1()
:
yi = interp1 (x0, y0, x, "linear")
err = 0.5 * max (abs ((yi - y) ./ (yi + y + eps))(:))
That is, err
is proportional to the maximum difference between the calculated and linearly interpolated values.err
is greater than tol
(2e-3 unless specified by the user) then put n = 2*(n-1) and repeat. Otherwise plot(x,y).Because abs(x)
is essentially a pair of straight lines, if x0 contains zero then the linearly interpolated values will always exactly match their corresponding calculated values and err
will be exactly zero, so the above algorithm will terminate at the end of the first iteration. If x doesn't contain zero then plot(x,y)
will be called on a set of points that doesn't include the 'cusp' of the function and the strange behaviour will occur.
This will happen if the limits are equally spaced either side of zero and floor(n/2 + 1) is odd, which is the case for the default values (limits = [-5, 5], n = 8).
The behaviour can be avoided by choosing a combination of n
and limits
so that either of the following is the case:
a) the set of m = floor(n/2 + 1) equally spaced points doesn't include zero or
b) the set of n equally spaced points does include zero.
For example, limits equally spaced either side of zero and odd n will plot correctly . This will not work for n=5, though, because, strangely, if the user inputs n=5, fplot.m
substitutes 8 for it (I'm not sure why it does this, I think it may be a mistake). So fplot(@abs, [-1, 1], 3)
and fplot(@abs, [-1, 1], 7)
will plot correctly but fplot(@abs, [-1, 1], 5)
won't.
(n/2 + 1) is odd, and therefore x0 contains zero for symmetrical limits, only for every 2nd even n. This is why it plots correctly with n=6 because for that value n/2 + 1 = 4, so x0 doesn't contain zero. This is also the case for n=10, 14, 18 and so on.
Choosing slightly asymmetrical limits will also do the trick, try: fplot(@abs, [-1.1, 1.2])
Upvotes: 2
Reputation: 743
The weird shape comes from the sampling rate, i.e. at how many points the function is evaluated. This is controlled by the parameter N
of fplot
The default call seems to accidentally skip x=0, and with fplot(@abs, [-1, 1], N=5)
I get the same funny shape like you:
However, trying out different values of N
can yield the correct shape, try e.g. fplot(@abs, [-1, 1], N=6)
:
Although in general I would suggest to use way higher numbers, like N=100
.
Upvotes: 0
Reputation: 926
The documentation says: "fplot works best with continuous functions. Functions with discontinuities are unlikely to plot well. This restriction may be removed in the future." so it is probably a bug/feature of the function itself that can't be fixed except by the developers. The ordinary plot()
function works fine:
x = [-1 0 1];
y = abs(x);
plot(x, y);
Upvotes: 1