These numerical methods answer part "b" in prompt. The answer to "a" is the MATLAB code in Appendix I
Brent's method takes the advantage of open methods (often faster root approximation) and the advantage of bracketing methods (more likely to converge on an answer) and combines them into one algorithm. The basic premise for this is the algorithm will first try either the secant method or inverse quadratic interpolation. If neither of these approaches appears to converge on a solution, or it will take too long to converge, the more conservartive "bracketing" method will be used. This method works only if the function evaluated at the two provided x-values have opposite signs (one is a negative y-value, the other is positive).
% Set xl and xu (upper and lower bounds) % Function call[root,ea] = brentMethod(xl,xu); %% Brent's method functionfunction [root,ea] = brentMethod(xl,xu) % Set values a = xl; b = xu;c = a; fc = fa; d = b - c; e = d; j = 0;eps = ___; while true j = j+1; if (fb == 0) break; end if sign(fa) == sign(fb) a = c; fa = fc; d = b - c; e = d; end if abs(fa) < abs (fb) THEN swap a and b end m = 0.5*(a - b); tol = 2*eps*max(abs(b),1); if (abs(m) <= tol) || (fb == 0) break; end % Determine which method to use if (abs(e) >= tol) && (abs(fc) > abs(fb)) (THEN DO AN OPEN METHOD) if a == c THEN Secant Method else THEN Inverse quadratic interpolation end IF else (DO Bisection method) end IF Approximate Error interpretation end DO root = b; end % End Brent functionThis method involves plotting the function and visually determining where it crosses the x-axis. As we can see from figure 2, the function f(x) = 0 at around x = -0.54 (red line). This method is useful as it builds visual intuition and enables us to easily find bracketing values for Brent's method.
The secant method takes the two provided values for x (where the function evaluates to opposite signs) and draws a line between them. Where this line crosses the x-axis becomes the new approximation for the root. Then a line is drawn from this new root approximation to the previous root approximation, and the process is repeated. Where this line crosses the x-axis becomes the new root approcimation.
Here we are going to use secant method, which is also one of the member methods in Brent's algorithm, to also solve our function. The results and number of required iterations will then be compared (in the discussion). Because the secant method is used in Brent's method, the iterations where the secant method is used will lead to similar root estimations. See appendix II for MATLAB code.
This analytical method answers part "d" in prompt
The "analytical" evaluation of the root involved using MATLAB's built-in "fzero" function. Here, we send input arguments including the function and the initial upper and lower x-bounds and the fzero command returns the root approximation. Given the function above and a = -5 and b = 0, fzero returns the exact same root of -0.539606511763780. Interestingly, "fzero" uses a form of Brent's method to approximate the root. So although we are comparing similar methods here, it is a good comfirmation that our Brent's method algorithm is working properly.
As we can see from the plots below, the approximate percentage error decreases at an almost identical rate. Depending on the tolerance set for the secant method, greater or fewer iterations may run. I chose a tolerance of 0.000001 which lead to the method converging at the same number of iterations as Brent's method. Looking at figure 4 below, we see how similar the drop in approximate error is (especially for the first few iterations). This is because, for the given function and initial x-coordinates, Brent's method chose to use the secant method for half of the total iterations. Brent's method first tries to use the secant method, and if it cannot it uses either inverse quadratic interpolation or the bisection method. For this particular function, tolerance, and initial bounds, the bracketing method was never used. The first iteration used secant method, the second used inverse quadratic interpolation, the third and fourth used secant, and the fifth and sixth used inverse quadratic interpolation. Because Brent's method used open methods for all iterations and the secant method for half of them, the error outcome is going to be relatively similar. As we can see from figure 4, Brent's method slightly outperforms the Secant method in convergence. This is to be expected, as Brent's method is choosing between multiple methods, including the secant method, for the quickest convergence to the root. It is for this reason Brent's method will often outperform most other root-finding methods.
Convergence can be expected as the function is "well-behaved" near the root, making it easy for the open methods to rapidly discern the root. We can see that for both Brent's method and the secant method, the root estimates converge to a value extremely close to our "analytical" solution -0.539606511763780 (given by "fzero" function). All of these results also agree with our root approximation from the graphical method, however my value from the graphical method is not to the same precision as the other approaches simply due to choice. I used the graphical method to inform my bracketing bounds for the other numerical methods, not to find a precise "analytical" value.
Comparing each iteration's approximation of the root to the "analytical"value can be seen in Figure 5. Figure 5 shows that after one iteration has completed, both Brent's method and the Secant method have true error values of ~75%. After the second iteration this drops to ~5%.
Given the problem setup above, our numerical approach will involve using Brent's method to find the root of f(Ta). Finding the root allows us to find Ta because where the function of f(Ta) = 0 is the Ta value that satisfies the originial equation. See Appendix III for MATLAB code. The root found using Brent's method was x = 1266.32436039989 and converged after 6 iterations. See Part 1 for an explanation of Brent's method, pseudocode, and a sample calculation.
The graphical method can also be used. In this case, I plotted the function first to find reasonable x-bounds to initialize Brent's method. Using the graphical method I determine the root was around 1.2663e+03, and this informed by x-bounds for Brent's method of x(lower) = 1000 and x(upper) = 1300.
The "analytical" method I chose for part 2 is MATLAB's built-in "fzero" function. This returned a root of x = 1266.32436039989, identical to the result from our numerical method (Brent's method).
As we can see from Figure 8 below, Brent's method rapidly converges and drops below the break criteria after 6 iterations. Interestingly, the approximate percent error starts at slightly over 2% (after the first iteration). This is because the "first pass" brought the root approximation significantly closer to the root. After three iterations the approximate error falls to 0.0035%. Convergence can be expected as the function is "well-behaved" near the root, making it easy for the open methods to rapidly discern the solution.
From figure 9 we can see that the approximations for Brent's method rapidly converge to our "analytical" solution 1266.32436039989 (given by "fzero" function). In fact, it converges to exactly the same value within 6 iterations (exceeding 10 decimal places of precision). The first iteration was below 0.6% away from our "true" value. This extremely small true error makes sense given the fact that the "fzero" function uses a method very similar to Brent's method. We are effectively sending the same function and bounds to almost an identical method. This exaplains the extremely small true error value.
Both of these results also agree with our root approximation from the graphical method.
%% To Analyze a general function, adjust "myfunction" and initial bounds % Set xl and xu (upper and lower bounds)xl = -5;xu = 0; % Function call[root,ea] = brentMethod(xl,xu); %% Brent's method functionfunction [root,ea] = brentMethod(xl,xu) % Epsiloneps = 2.22044604925031e-16; % Set values a = xl; fa = myfunction(a);b = xu; fb = myfunction(b);c = a; fc = fa;d = b - c; e = d;j = 0;b_old = b; while true j = j+1; %Increment if (fb == 0) break; end if sign(fa) == sign(fb) a = c; fa = fc; d = b - c; e = d; end if abs(fa) < abs (fb) c = b; b = a; a = c; fc = fb; fb = fa; fa = fc; end m = 0.5*(a - b); tol = 2*eps*max(abs(b),1); if (abs(m) <= tol) || (fb == 0) break; end % Determine which method to use % Open methods if (abs(e) >= tol) && (abs(fc) > abs(fb)) s = fb/fc; % Secant Method if a == c p = 2*m*s; q = 1 - s; % Inverse quadratic interpolation else q = fc / fa; r = fb / fa; p = s * ((2*m*q*(q-r)) - ((b-c)*(r-1))); q = (q - 1)*(r - 1)*(s - 1); end if p > 0 q = -q; else p = -p; end if (2*p < 3*m*q - abs(tol*q)) && (p < abs(0.5*e*q)) e = d; d = p/q; else d = m; e = m; end % Bisection method else d = m; e = m; end c = b; fc = fb; if abs(d) > tol b = b + d; else b = b - sign(b-a)*tol; end fb = myfunction(b); % Error ea(j) = abs((b-b_old)/b)*100; b_old = b; end % END while root = b; %Final root end % End function %% Function to be analyzedfunction f = myfunction(x)f = -12 - 21.*(x) + (x.^2) - 2.4.*(x.^3);end%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Name: Bryan Bennett% Purpose of code: To provide algorithms for assessing the roots of% functions. A real-world example is also implemented%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% clear all; close all; %% To Analyze a general function, adjust "myfunction" and initial bounds % Set xl and xu (upper and lower bounds)xl = -5; xu = 0; % Function call[root_brent,ea_brent,et_brent,maxiter_brent] = brentMethod(xl,xu);[root_sec,ea_sec,et_sec,maxiter_sec] = secantMethod(xl,xu); % Analytical solutionx_root_analytical = fzero(@myfunction,[xl xu]); %% Plots x = [xl:0.0001:xu];y = myfunction(x); % Plotting function for graphical analysisfigure(1)hold all;plot(x,y,'-.', 'LineWidth',3,'Markersize',3,'Color','g');xline(root_brent,'r');xline(0); yline(0);xlabel('Function input');ylabel('Function output');title('Graphical Method For Determining Root');xlim([-2 1]);ylim([-10 50]);legend('f(x)', 'location', 'northeast')box on; grid on; % Plotting ea / convergence for Brent's methodj = [1:1:maxiter_brent];figure(2)hold all;plot(j,ea_brent,'-', 'LineWidth',3,'Markersize',3,'Color','r');xlabel('Number of Iterations (j)');ylabel('Approximate Percentage Error (%)');title('Observing Convergence in Brents Method');legend('ea(j)', 'location', 'northeast')box on; grid on; % Plotting ea / convergence for Secant methodk = [1:1:maxiter_sec];figure(3)hold all;plot(k,ea_sec,'-', 'LineWidth',3,'Markersize',3,'Color','b');xlabel('Number of Iterations (k)');ylabel('Approximate Percentage Error (%)');title('Observing Convergence in Secant Method');legend('ea(k)', 'location', 'northeast')box on; grid on; %% Brent's method functionfunction [root,ea,et,iter] = brentMethod(xl,xu) % Epsilon (used to determine tolerance, so is a factor in break conditions) eps = 2.22044604925031e-16; % Set values. "a" and "b" bracket root, and are updated as the iterations% converge towards solutiona = xl; fa = myfunction(a); b = xu; fb = myfunction(b); c = a; fc = fa; % Used as in intermediate variable for evaluating root approximationsd = b - c; % Used to update new root approximations. Represents a distance and x-coordinatee = d; % Used to track important x-coordinates as methods update valuesj = 0; % Iteratorb_old = b; % Used in error approximationroot_true = fzero(@myfunction,[xl xu]); % Used for true error while true j = j+1; %Increment if (fb == 0) break; end if sign(fa) == sign(fb) a = c; fa = fc; d = b - c; e = d; end %If f(a) is closer to x-axis than f(b), Swap a and b % This ensures b is always the better approximation if abs(fa) < abs (fb) c = b; b = a; a = c; fc = fb; fb = fa; fa = fc; end % Used to assess increments in x with successive iterations. % Important for breaking criteria m = 0.5*(a - b); % "Tolerance". Important for all iterative methods % Adjusts with each increment, provides basis for break criteria and method selection tol = 2*eps*max(abs(b),1); % Break criteria (needed despite other break command above, because % of operations subsequently performed) if (abs(m) <= tol) || (fb == 0) break; end % Determine which method to use % Open methods if (abs(e) >= tol) && (abs(fc) > abs(fb)) s = fb/fc; % Secant Method if a == c p = 2*m*s; q = 1 - s; display("secant "+j) % Inverse quadratic interpolation % Notice how "f(somevalue)" are being used. This is because it % is inverse interpolation so y-values effectively are % x-coordinates with the domain and range swapped. else q = fc / fa; r = fb / fa; p = s * ((2*m*q*(q-r)) - ((b-c)*(r-1))); q = (q - 1)*(r - 1)*(s - 1); display("inverse quadratic interpolation "+j) end if p > 0 q = -q; else p = -p; end if (2*p < 3*m*q - abs(tol*q)) && (p < abs(0.5*e*q)) e = d; d = p/q; else d = m; e = m; end % Bisection method. This is default if an open method criteria are not met else d = m; e = m; display("bisection method "+j) end c = b; fc = fb; % Update "b" with new root approximation if abs(d) > tol b = b + d; else b = b - sign(b-a)*tol; end % Used as break-criteria for next iteration fb = myfunction(b); % Error ea(j) = abs((b-b_old)/b)*100; et(j) = abs((root_true-b)/root_true)*100; b_old = b; end % END while root = b; %Return final root iter = j - 1; %Return number of iterations end % End function %% Secant method functionfunction [root,ea,et,iter] = secantMethod(xl,xu)k = 0;a = xl; b = xu;tol = 0.000001; % Changing this will change the total iterationsroot_true = fzero(@myfunction,[xl xu]); while true k = k+1; fa = myfunction(a); fb = myfunction(b); c = b - (fb*(a-b)/(fa-fb)); ea(k) = abs((c-b)/c)*100; et(k) = abs((root_true-c)/root_true)*100; if (ea(k) <= tol) display("break") break; end a = b; b = c; end root = c; iter = k; end %% Function to be analyzedfunction f = myfunction(x)f = -12 - 21.*(x) + (x.^2) - 2.4.*(x.^3);endclear all; close all; %% Declare Variables% Set xl and xuxl = 1000;xu = 1300; % Function call[root,ea,et,maxiter] = brentMethod(xl,xu); % Analytical "true" solutionx_root_analytical = fzero(@myfunction,[xl xu]); %% Plots x = [xl:0.01:xu];y = myfunction(x); % Plotting function for graphical analysisfigure(1)hold all;plot(x,y,'-.', 'LineWidth',3,'Markersize',3,'Color','g');xline(root,'r');yline(0);xlabel('Function input (Ta)');ylabel('Function output f(Ta)');title('Graphical Method For Determining Root');xlim([xl xu]);%ylim([-10 50]);legend('f(Ta)', 'location', 'northeast')box on; grid on; % Plotting approximate percentage error (convergence) for Brent's methodj = [1:1:maxiter];figure(2)hold all;plot(j,ea,'-', 'LineWidth',3,'Markersize',3,'Color','r');xlabel('Number of Iterations (j)');ylabel('Approximate Percentage Error (%)');title('Observing Convergence in Brents Method');legend('ea(j)', 'location', 'northeast')box on; grid on; % Plotting "true" percentage error for Brent's methodj = [1:1:maxiter];figure(3)hold all;plot(j,et,'-', 'LineWidth',3,'Markersize',3,'Color','b');xlabel('Number of Iterations (j)');ylabel('True Percentage Error (%)');title('True Percentage Error with Brents Method');legend('et(j)', 'location', 'northeast')box on; grid on; %% Brent's method functionfunction [root,ea,et,iter] = brentMethod(xl,xu) % Epsiloneps = 2.22044604925031e-16; % Set values a = xl; fa = myfunction(a); b = xu; fb = myfunction(b);c = a; fc = fa;d = b - c; e = d;j = 0;b_old = b; % We use this as our "true" valueroot_true = fzero(@myfunction,[xl xu]); while true j = j+1; %Increment if (fb == 0) break; end if sign(fa) == sign(fb) a = c; fa = fc; d = b - c; e = d; end if abs(fa) < abs (fb) c = b; b = a; a = c; %If a is closer to x-axis, Swap a and b fc = fb; fb = fa; fa = fc; end m = 0.5*(a - b); tol = 2*eps*max(abs(b),1); if (abs(m) <= tol) || (fb == 0) break; end % Determine which method to use % Open methods if (abs(e) >= tol) && (abs(fc) > abs(fb)) s = fb/fc; % Secant Method if a == c p = 2*m*s; q = 1 - s; % Inverse quadratic interpolation else q = fc / fa; r = fb / fa; p = s * ((2*m*q*(q-r)) - ((b-c)*(r-1))); q = (q - 1)*(r - 1)*(s - 1); end if p > 0 q = -q; else p = -p; end if (2*p < 3*m*q - abs(tol*q)) && (p < abs(0.5*e*q)) e = d; d = p/q; else d = m; e = m; end % Bisection method else d = m; e = m; end c = b; fc = fb; if abs(d) > tol b = b + d; else b = b - sign(b-a)*tol; end fb = myfunction(b); % Error ea(j) = abs((b-b_old)/b)*100; et(j) = abs((root_true-b)/root_true)*100; b_old = b; end % END while root = b; %Final root iter = j - 1; end % End function %% Function to be evaluated function f = myfunction(x)f = (x./10).*(cosh(500./x)) - (10) - (x./10);end