Reputation: 45
I made a function (bisection) that calculates the zero of a function (like fzero) using the bisection method, however when I run the function I get the following warning: "Warning: Function behaves unexpectedly on array inputs. To improve performance, properly vectorize your function to return an output with the same size and shape as the input arguments."
No idea how to solve this.
bisection function
function[x, output, graf] = bisection(f, x0, TOL, NMAX)
graf = "no";
if(nargin > 1)
if (~exist('TOL','var') || TOL == '~')
TOL = eps;
end
if (~exist('NMAX','var') || NMAX == '~')
NMAX = 500;
end
else
error('Too few input arguments');
end
if isa(f, 'function_handle')
% f is a function
else
error('f is not a function!');
end
if isvector(x0)
disp(size(x0));
if (size(x0) > 2)
error('x0 has too many elements!');
else
if(size(x0) < 2)
error('x0 has too few elements!');
end
end
if ~isnumeric(x0(1)) || ~isnumeric(x0(2))
error('Elements of x0 must be numeric!');
end
if x0(1)>x0(2)
error('x0(1) is > than x0(2)');
end
else
error('x0 is not a vector!');
end
if f(x0(1))*f(x0(2)) > 0
error('There are no zeros!');
end
if ~isnumeric(NMAX)
error('NMAX must be a number');
else
if floor(NMAX) ~= NMAX
error('NMAX must be integer');
end
end
if ~isnumeric(TOL)
error('TOL must be numeric!');
end
x0 = [x0(1), x0(2)];
[x, output] = do_bisection(f,x0,TOL,NMAX);
output = [ output(1), NMAX - output(2) ];
if("yes" == "yes")
fplot(f,[x0(1)*2, x0(2)*2]);
title(strcat('Grafico f = ',func2str(f)));
xlabel('x');
ylabel('y = f(x)');
grid on;
grid minor;
set(gca,'xaxislocation','origin');
set(gca,'yaxislocation','origin');
hold on;
fplot(@(x) 0,[x0(1), x0(2)],'r -');
plot(x,f(x),'k s');
text(x0(1), 0.5, strcat('a=',num2str(x0(1))));
text(x0(2), 0.5, strcat('b=',num2str(x0(2))));
text(x, -0.5, strcat('x=',num2str(x)));
graf = "yes";
end
end
do_bisection
function[x, output] = do_bisection(f, x0, TOL, NMAX)
a = x0(1);
b = x0(2);
if f(a)*f(b)>0
error('non ci sono zeri');
end
iter = 0;
c = (a+b)/2;
while(iter<NMAX && (((abs(x0(2)-x0(1))/max(abs(x0(1)),abs(x0(2))))>TOL) && (abs(f(c)) > eps)))
if(f(c)*f(a) < 0)
b = c;
else
a = c;
end
c = (a +b)/2;
iter = iter +1;
end
x = c;
output = [ f(c), iter ];
end
I call the function
f = @(x) x^2 - 5;
x0 = [1, 3];
[x, out, graf] = bisection(f,x0,10.^(-5),500);
Upvotes: 1
Views: 6654
Reputation: 1316
Your code runs fine and your bisection algorithm seems to be correctly implemented. The warning message that appears is because of the call to fplot function.
fplot(f,[x0(1)*2, x0(2)*2]);
This function automatically plots the function f
defined as a function handle. It warns you, however, that your function f
is not properly vectorized. To get rid of the warning, just change your function definition
f = @(x) x^2 - 5;
to
f = @(x) x.^2 - 5;
Notice that the .^
indicates an element-wise exponentiation. If you simply write x^2
, MATLAB will try to do a matrix multiplication instead.
This warning will also appear on the other fplot
call. Change it to:
fplot(@(x) 0.*x,[x0(1), x0(2)],'r -');
And ou should be fine. This time, I just multiply the 0
for the array x
. Essentially, the results are the same. However, multiplying 0
by x
automatically takes into consideration the array size.
With only this changes, the function runs fine without any warnigs, and produce the desired output:
Upvotes: 1
Reputation: 30047
You can debug this...
The full warning looks like this:
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly vectorize your function to return an output with the same size and shape as the input arguments.
[...]
In fplot (line 161)
In bisection (line 70)
Line 70 of bisection
is this one:
fplot(@(x) 0,[x0(1), x0(2)],'r -');
The function you're supplying is @(x)0
, which returns a scalar 0
for a vector input (which fplot
creates). Therefore the error makes sense, you're inputting an array to @(x)0
, which doesn't properly handle arrays!
Two solutions:
Properly define your anonymous function to handle array inputs x
fplot( @(x) zeros(size(x)), [x0(1), x0(2)], 'r-' );
Use a quicker function than fplot
to simply draw a line at y=0
between your two x0
points.
plot( x0(1:2), [0 0], 'r-' );
I'm suggesting plot
because all you're trying to do is plot a straight line between two points. fplot
is creating an array under the hood to do this for you, but it's overkill here, and plot
is a simpler function! You could also use line
which is even simpler but has slightly different syntax to specify styles.
Similarly, you need to change the definition of f
to handle arrays properly by using the element-wise power operator:
f = @(x) x.^2 - 5;
Upvotes: 1