mirror of
https://github.com/kuhyx/WUT_Computer_Science.git
synced 2026-07-04 19:43:03 +02:00
115 lines
3.7 KiB
Matlab
115 lines
3.7 KiB
Matlab
% define available algorithms
|
|
algorithms = {
|
|
'MM1', @mm1;
|
|
'MM2', @mm2
|
|
};
|
|
|
|
% find all real root brackets
|
|
interval = [1, 7];
|
|
brackets = rootbrac(@polynomial, interval(1), interval(2));
|
|
|
|
% find and graph real roots using both algorithms
|
|
printroots(@polynomial, algorithms, interval, brackets, ...
|
|
'Approximate real roots of polynomial', 'realroots');
|
|
printcomplex(@polynomial, algorithms, [-1+i, 0], ...
|
|
'Approximate complex roots of polynomial', 'complexroots');
|
|
|
|
% find roots of polynomial using MM1
|
|
function [zero, steps] = mm1(func, a, b, tolerance)
|
|
% define the three approximation points
|
|
apprx = [a, b, (a + b) / 2];
|
|
apprxval = arrayfun(func, apprx);
|
|
|
|
% initialize output
|
|
steps = [apprx(3); func(apprx(3))];
|
|
|
|
% iterate algorithm until the error is within tolerance
|
|
while abs(apprx(3) - apprx(2)) > tolerance
|
|
% prepare linear equation system to find parabola
|
|
z0 = apprx(1) - apprx(3);
|
|
z1 = apprx(2) - apprx(3);
|
|
diff0 = apprxval(1) - apprxval(3);
|
|
diff1 = apprxval(2) - apprxval(3);
|
|
|
|
% solve equation system using Gaussian elimination (spaghetti code but fast)
|
|
eqsys = [z0 ^ 2, z0, diff0; z1 ^ 2, z1, diff1];
|
|
reductor = eqsys(2, 1) / eqsys(1, 1);
|
|
eqsys(2, :) = eqsys(2, :) - reductor * eqsys(1, :);
|
|
eqsys(2, 1) = 0;
|
|
eqsys(2, :) = eqsys(2, :) ./ eqsys(2, 2);
|
|
eqsys(1, :) = eqsys(1, :) - eqsys(1, 2) * eqsys(2, :);
|
|
eqsys(1, :) = eqsys(1, :) ./ eqsys(1, 1);
|
|
|
|
% define approximation parabola
|
|
a = eqsys(1, 3);
|
|
b = eqsys(2, 3);
|
|
c = apprxval(3);
|
|
|
|
% find roots of parabola
|
|
zplus = -2 * c / (b + sqrt(b ^ 2 - 4 * a * c));
|
|
zminus = -2 * c / (b - sqrt(b ^ 2 - 4 * a * c));
|
|
|
|
% choose root closer to current approximation
|
|
if abs(zplus) < abs(zminus)
|
|
newapprx = apprx(3) + zplus;
|
|
else
|
|
newapprx = apprx(3) + zminus;
|
|
end
|
|
|
|
% update answer
|
|
zero = newapprx;
|
|
steps(:, size(steps, 2) + 1) = [zero, func(zero)];
|
|
|
|
% eliminate the most distant of the three approximations
|
|
worstapprxindex = -1;
|
|
worstapprxdiff = 0;
|
|
for i = 1:size(apprx, 2)
|
|
diff = abs(apprx(i) - newapprx);
|
|
if diff > worstapprxdiff
|
|
worstapprxindex = i;
|
|
worstapprxdiff = diff;
|
|
end
|
|
end
|
|
|
|
% delete old approximation and append new one
|
|
apprx(worstapprxindex) = [];
|
|
apprx(3) = newapprx;
|
|
apprxval = arrayfun(func, apprx);
|
|
end
|
|
end
|
|
|
|
% find roots of polynomial using MM2
|
|
function [approx, steps] = mm2(func, a, b, tolerance)
|
|
% define current and (dummy) previous approximation point
|
|
approx = (a + b) / 2;
|
|
prevapprox = approx + b - a;
|
|
|
|
% initialize output
|
|
steps = [approx; func(approx)];
|
|
|
|
% iterate algorithm until the error is within tolerance
|
|
% the error is defined as the diff between the prev and the current approx
|
|
while abs(approx - prevapprox) > tolerance
|
|
% calculate approximating parabola using first and second derivative
|
|
c = func(approx);
|
|
b = deriv(func, approx, 1);
|
|
a = deriv(func, approx, 2) / 2;
|
|
|
|
% find roots of parabola
|
|
zplus = -2 * c / (b + sqrt(b ^ 2 - 4 * a * c));
|
|
zminus = -2 * c / (b - sqrt(b ^ 2 - 4 * a * c));
|
|
|
|
% choose root closer to current approximation
|
|
if abs(zplus) < abs(zminus)
|
|
newapprox = approx + zplus;
|
|
else
|
|
newapprox = approx + zminus;
|
|
end
|
|
|
|
% update answer and prev approx
|
|
prevapprox = approx;
|
|
approx = newapprox;
|
|
steps(:, size(steps, 2) + 1) = [approx, func(approx)];
|
|
end
|
|
end
|