Finding the zeros of a function
Show older comments
I need to find where y=0 within 0<x<100
y=5*sin(1.9*x)+2.1*sin(9.1*x)
Accepted Answer
More Answers (6)
Alan Weiss
on 8 Oct 2013
0 votes
Walter Roberson
on 8 Oct 2013
0 votes
There are 11 zeros in that range. You can eyeball the plot to approximate the ranges and then fzero() over the distinct ranges.
You are not going to be able to find closed form solutions for the zeros; it involves roots of two 90th degree polynomials.
2 Comments
Alan Weiss
on 9 Oct 2013
Actually, I get 85 distinct roots (84 if we don't count 0). Some are quite close together.
fun = @(x)5*sin(1.9*x)+2.1*sin(9.1*x);
t = 0:.01:100;
for ii = 1:length(t)
yy(ii) = fzero(fun,t(ii));
end
zz = unique(yy);
zz = sort(zz);
z = round(1e9*zz)*1e-9; % Get rid of spurious differences
z = unique(z);
q = find(z>100);
z(q) = [];
Alan Weiss
MATLAB mathematical toolbox documentation
Walter Roberson
on 25 Jun 2015
I was not able to figure out later why I thought there were only 11!
I can say, though, that this question led me to filing a bug report against a different manufacturer's software ;-)
Dennis Yeh
on 6 Dec 2014
Edited: Walter Roberson
on 8 May 2015
EDIT: I suggested this solution in the past, but found that it does not work well.
% Find all intersections of y1 and y2, where x is the independent variable:
x = linspace(0,10,10000); y1 = sin(x); y2 = cos(x);
coeff = polyfit(x,(y2-y1),100); % Perform a degree 100 polynomial curve fit on the difference between y1 and y2.
possible_zeros = sort(unique(abs(roots(coeff)))); % Roots of the polynomial curve fit - the absolute value is to convert complex roots, and the unique() function turns each complex pair to only 1 point
error = polyval(coeff,possible_zeros); % Evaluate the polynomial curve fit at every root - answers close to zero correspond to an intersection
tolerance = 1e-6; % Change this value to be larger if intersections are skipped, and smaller if fake intersections are returned
actual_zeros_indices = find(abs(error) < tolerance); % Find the indices of the vector "possible_zeros" that correspond to actual zeros
actual_zeros = possible_zeros(actual_zeros_indices); % Plug the indices into possible_zeros to find the real zeros
f1 = figure(1);
subplot(2,1,1);
plot(x,y1,x,y2); % Plot the original functions
subplot(2,1,2);
plot(x,(y2-y1),'b',x,polyval(coeff,x),'g',actual_zeros,polyval(coeff,actual_zeros),'r*') % Plot the difference between y1 and y2, the curve fit, and the zeros
1 Comment
John D'Errico
on 6 Dec 2014
Please don't tell people to do 100 degree polynomial fits with polyfit, or with ANY tool in double precision! The coefficients that arise will be essentially numerical garbage. I'm sorry, but this solution is terrible advice.
Mauricio Redaelli
on 25 Jun 2015
Sorry, it´s an old post. Hope you don´t mind. I solved using this:
% code
s = sign(y);
s(isnan(s))=[];
rr = find(sign(y)==0); %look up for machine number zeros
r = find(([s(1) s]==[s s(end)])==0); %look up for nearby machine number zeros
if isempty(rr)
return
else
r((rr+1)==r)=[]; %get rid of duplicities
r((rr-1)==r)=[];
end

3 Comments
Walter Roberson
on 25 Jun 2015
What is your "y" here? Considering you are using find() on something produced from y, it appears that y must be a numeric vector rather than a symbolic expression. But if it is a numeric vector then how do you know how fine-grained to make the vector? I see your plot talks about step sizes but the code you posted does not; how do you know that you have probed finely enough ?
You could keep going finer until you stopped generating more crossings, but then in the general case you run into the possibility that there are two zeros very close together, such that you might need to refine down several decimal places to tell them apart.
Mauricio Redaelli
on 29 Jun 2015
You are right, y was genereted according to the expression provided. But this code compares the sign of y to the signs of the one-element-translated y. They will be all equal, except right on the zeros. It doens´t matter how fine-grained is the vector, because the sign will have the same step, and the transition from 1 to -1 occurs only in on point, right? I´m really curious to verify where this could be wrong, as I really am a novice.
This is my first post and my first answer, so pardon my english flaws. Thank you.
Walter Roberson
on 29 Jun 2015
f = @(x) 5*sin(1.9*x)+2.1*sin(9.1*x); %from above
y = f(linspace(0,100,2));
How many of the zeros do you detect in y?
y = f(linspace(0,100,10));
How many of the zeros do you detect in this y?
x = linspace(0,100,500);
y = f(x);
There, 500 points sampled for what we happen to know are 85 roots. If it does not matter how fine-grained the vector y is, then 500 points should be enough to find all of the roots. But your code returns 78 roots.
plot(x,y,'b-', x(r), y(r), 'r*');
Now try with x = linspace(0,100,790); and observe that your code counts 84 roots (your code is discarding the root at 0 which is the 85th root.) But then try with x = linspace(0,100,800); and observe that your code counts only 76 roots. How can increasing how close together the samples are result in fewer roots being found? How is someone to know that it is safe to use 790 samples but that 800 will not find all of the roots?
Mauricio Redaelli
on 29 Jun 2015
0 votes
Walter, this is very interesting. It seems to me that x=0 will never be found because the sign(y) will never see a transition, as we have none negative values. It´s a bug and should be fixed. Another bug is that the roots I found is not always the closest to the zero line - they always lay after the transition. I must easily fix it adding a new r = find(...) line, but moving the sign vector for the left, and then comparing those two r vectors. Another interesting point of discussion is the number of roots as a function of the x step. Well, for me this is an issue that should be on the concern of who build the y vector. If the function is not suficiently fine-grained to solve all the roots, so be it. Check the figure. Thank you again for the discussion!

2 Comments
Walter Roberson
on 29 Jun 2015
But the original poster didn't even know how many zeros there were in the range (I wouldn't either, not just be looking at that function!). How would they know whether they had used enough points in the vector?
Remember, the original poster did not give a vector of samples: the original poster gave an expression, and you choose to interpret it in terms of sampling over a vector of locations, so you as the proposer have a responsibility to say how to choose that vector in order to be sure of getting all of the roots.
Mauricio Redaelli
on 30 Jun 2015
I agree with you, but I can't provide a general rule of sampling to be sure we will get all of the roots. Maybe my algorithm is not suficient to find roots af any function in any condition, but sampling is an analytical task one must do in every case, not only to find roots. Anyway, thank you a lot for the discussion!
Categories
Find more on Solver Outputs and Iterative Display in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!