我试图测试在Matlab中使用两种方法查找函数根的效率。为了做到这一点,我计算每个方法所采用的迭代,然后将其绘制为各种容差值(f(root)与0的接近程度)。出于某种原因,当我计算迭代值并将它们保存到向量时 - 因为不同的容差有不同的值 - 向量似乎只填充0.我对此感到困惑,因为我写的函数不应该是返回0作为迭代值。这是我的所有代码:
function cooldrive()
a = 0.1; b = 3;
tol = 0.01;
L = 1:0.1:4;
r_x = zeros(1, length(L));
ctr = 1;
for i=L
[x, iter] = bis(a, b, tol, i);
r_x(ctr) = x;
ctr = ctr+1;
b = x;
end
r_x = r_x.^2;
figure
plot(L, r_x, '.-b', 'markersize', 16)
ylabel('Decay Rate, x^2'), xlabel('Length, L'), title('Cooling Rate')
grid
x = (a+b)/2;
r_iter_newt = zeros(1, 8);
r_iter_bis = zeros(1, 8);
r_tol = zeros(1, 8);
ctr = 1;
for j=1:8
tol = 10^(-1*j);
[x_newt, iter_newt] = newt(x, tol, 1);
[x_bis, iter_bis] = bis(a, b, tol, 1);
b = x_bis;
r_iter_newt(ctr) = iter_newt;
r_iter_bis(ctr) = iter_bis;
r_tol(ctr) = tol;
ctr = ctr+1;
end
figure
plot(r_tol, r_iter_newt, '.-r', 'markersize', 16)
hold on
plot(r_tol, r_iter_bis, '.-b', 'markersize', 16);
hold off
return
%% Bisection Method
function [x, iter] = bis(a, b, tol, L)
iter = 0;
z1 = coolfun(a, L);
z2 = coolfun(b, L);
if z1 * z2 > 0
disp('Root may not exist')
x = NaN;
iter = NaN;
return
end
x = (a+b)/2;
while abs(coolfun(x, L)) > tol
if (coolfun(a,L)*coolfun(x,L)) <= 0
b = x;
else
a = x;
end
x = (a+b)/2;
iter = iter + 1;
end
%[x, iter] = bis(a, b, tol, L);
return
%% Newton's Method
function [ox, iter] = newt(ix, tol, L)
iter = 0;
while abs(coolfun(ix, L)) > tol
x_j = ix - (coolfun(ix, L)/coolfundx(ix, L));
ix = x_j;
iter = iter+1;
end
ox = ix;
return
%% Evaluate function
function val = coolfun(x, L)
val = sin(x*L) + x*cos(x*L);
return
%% Evaluate Function's Derivative
function val = coolfundx(x, L)
val = (L*cos(x*L)) - (L*x*sin(x*L)) + cos(x*L);
return
在上面的代码中,iter_bis的值总是0,所以r_iter_bis中的值是NaN,0,0,....我看不出发生这种情况的原因。
答案 0 :(得分:1)
问题是你测试根存在。
z1 = coolfun(a, L);
z2 = coolfun(b, L);
if z1 * z2 > 0
disp('Root may not exist')
但是,由于您尝试解决的函数不是单调的,因此可以使两个终点为正,但中间点为负(反之亦然)。在这种情况下,存在多个零,但是您的测试表明它们没有,并且您的代码将停在那里。
问题在于方法。二分法对非单调函数不起作用。您必须知道,根据您的函数值是正还是负,哪种方式移动以接近零,但如果您的函数不是单调的,那么您不知道。
您需要限制二分搜索域以使该函数单调,或使用其他方法。