How to find a root and know if fsolve or fzero is better?

91 views (last 30 days)
Dear expert,
Can you please help how to find the root of the following function and pass parameters such as Z, X_mem, phi, C_surf so that I can use the value of the solver by calling the function to another function?
And if fsolve or fzero is better?
Z=[-1 1 -1]
X_mem = -0.5
phi= [0.7 0.8 0.9]
C_surf=[0.001 0.002 0.003]
f= @(k) Z(1)*k + X_mem + Z(2)*phi(2)*C_surf(2)*(k/(phi(1)*C_surf(1)))^(Z(2)/Z(1))...
+ Z(3)*phi(3)*C_surf(3)*(k/(phi(1)*C_surf(1)))^(Z(3)/Z(1));
Thank you in advance for your help.

Accepted Answer

John D'Errico
John D'Errico on 19 Feb 2023
Edited: John D'Errico on 22 Feb 2023
IF you have a function of more than one variable, you ALWAYS need to use fsolve. fzero would not apply.
IF you have a function of only one variable, thus in your example f(k), then fzero will almost always be preferred. Why? fzero does some things that attempt to make it more robust against problems. It is designed to be a very good rootfinding code in ONE dimension. On the other hand, fsolve is designed to solve problems in multiple dimensions. It has none of the protections that fzero has built into it.
Next, fzero can accept a bracket. If you have a pair of points that bracket a solution, then fzero will ALWAYS converge to some solution, and it will do so in a robust, stable way.
If you do not have a bracket around the solution, so only one point, then fzero will attempt to find a bracket starting from that point that does contain a solution, but it is always happier if you give it a bracket.
The only flaw with fzero in this respect is if you do supply a bracket that does not have different signs at each end point, then it will fail, in a circumstance where fsolve MAY have succeeded. But had you given only one start point to fzero on the same problem, it too would often have worked, if a solution could be found.
Conversely, there may be some start points for fsolve where it may diverge, when fzero may be successful.
In general, IF you can use fzero, then I would always recommend fzero. Both solvers will be relatively fast, no matter what. But fzero has much going for it. If you can though, I would also always recommend providing a bracket for fzero.
For example:
f = @(x) exp(x) - 2;
We know the solution is in fact log(2)
format long g
log(2)
ans =
0.693147180559945
Now try both optimizers.
opts = optimset('Display','iter');
fzero(f,5,opts)
Search for an interval around 5 containing a sign change: Func-count a f(a) b f(b) Procedure 1 5 146.413 5 146.413 initial interval 3 4.85858 126.841 5.14142 168.959 search 5 4.8 119.51 5.2 179.272 search 7 4.71716 109.85 5.28284 194.929 search 9 4.6 97.4843 5.4 219.406 search 11 4.43431 82.2943 5.56569 259.304 search 13 4.2 64.6863 5.8 328.3 search 15 3.86863 45.8767 6.13137 458.066 search 17 3.4 27.9641 6.6 733.095 search 19 2.73726 13.4446 7.26274 1424.16 search 21 1.8 4.04965 8.2 3638.95 search 22 0.474517 -0.392763 8.2 3638.95 search Search for a zero in the interval [0.474517, 8.2]: Func-count x f(x) Procedure 22 0.474517 -0.392763 initial 23 0.47535 -0.391422 interpolation 24 0.71876 0.0518874 interpolation 25 0.69027 -0.005746 interpolation 26 0.69311 -7.34106e-05 interpolation 27 0.693147 1.79306e-09 interpolation 28 0.693147 -3.28626e-14 interpolation 29 0.693147 0 interpolation Zero found in the interval [0.474517, 8.2]
ans =
0.693147180559945
As you can see, fzero spent a fair amount of time wasted, searching for a bracket that contains the solution. In fact, you can see fzero operated in tow modes, first searching for a bracket, and then, once if had a bracket, it zoomed into the oslution nicely. Had I just given fzero a bracket initially though. fzero converges quite rapidly.
fzero(f,[0,10],opts)
Func-count x f(x) Procedure 2 0 -1 initial 3 0.00045402 -0.999546 interpolation 4 0.999728 0.717542 interpolation 5 0.582148 -0.210121 interpolation 6 0.676732 -0.0325618 interpolation 7 0.693325 0.000355115 interpolation 8 0.693146 -2.92221e-06 interpolation 9 0.693147 -2.594e-10 interpolation 10 0.693147 0 interpolation Zero found in the interval [0, 10]
ans =
0.693147180559945
By way of comparison, fsolve took more time to converge, but it did not need a bracket.
fsolve(f,5,opts)
Norm of First-order Trust-region Iteration Func-count f(x) step optimality radius 0 2 21436.8 2.17e+04 1 1 4 2845.04 0.986524 2.95e+03 1 2 6 365.087 0.963859 403 1 3 8 42.7281 0.905246 55.8 1 4 10 3.87915 0.765717 7.82 1 5 12 0.173812 0.496165 1.01 1.91 6 14 0.00115438 0.172496 0.0691 1.91 7 16 7.96378e-08 0.0167043 0.000564 1.91 8 18 3.96217e-16 0.000141081 3.98e-08 1.91 Equation solved. fsolve completed because the vector of function values is near zero as measured by the value of the function tolerance, and the problem appears regular as measured by the gradient.
ans =
0.69314719051255
Finally, you might notice that fsolve did not yield quite as good of a solution, whereas fzero gave virtually full double precision. Fsolve stopped at a point where it was happy.
log(2)
ans =
0.693147180559945
Again, if you can use fzero, then do so. Best, give it a bracket around a root, even if the bracket is quite wide.

More Answers (0)

Categories

Find more on Optimization in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!