我想为以下函数找到一个根,误差小于0.05%
f= 3*x*tan(x)=1
在MatLab中我写了这样的代码:
clc,close all
syms x;
x0 = 3.5
f= 3*x*tan(x)-1;
df = diff(f,x);
while (1)
x1 = 1 / 3*tan(x0)
%DIRV.. z= tan(x0)^2/3 + 1/3
er = (abs((x1 - x0)/x1))*100
if ( er <= 0.05)
break;
end
x0 = x1;
pause(1)
end
但它继续运行一个无限循环,错误200.00我不知道为什么。
答案 0 :(得分:0)
不要使用while true
,因为这通常是不必要的,并且容易陷入无限循环,就像这里一样。只需在while
上设置限制:
while er > 0.05
%//your code
end
此外,为了防止陷入无限循环,您可以使用迭代计数器并设置最大迭代次数:
ItCount = 0;
MaxIt = 1e5; %// maximum 10,000 iterations
while er > 0.05 & ItCount<MaxIt
%//your code
ItCount=ItCount+1;
end
答案 1 :(得分:0)
我认为我将分别讨论四个问题:
为什么错误看似在200.0饱和并且循环无限延续?
定义迭代器,如代码中所写,正在寻找f(x) = x - tan(x)/3
的根;换句话说,找到x
与x
的图形交叉的tan(x)/3
值。这是真的唯一的一点是0
。而且,如果您查看迭代的值,x1
的值即将接近0
。好。
坏消息是你也将这个值除以0
。虽然x1
的值仍然是有限的,但在浮点算术意义上,除法有效但可能会变得不准确,er
在经过足够的迭代后实际上会NaN
因为x1
下溢低于IEEE-754标准中最小的非规范化数字。
为什么er
200之前呢?它大约为200,因为x1
的值约为x0
值的1/3,因为tan(x)/3
本地表现为x/3
,其泰勒展开约{{1} }}。并0
。
除零和相对数量级是有时最好查看的绝对和相对错误度量值的原因。自变量和函数值。如果需要的话,即使在相对计算的分母中放置一个极其(相对)小的有限,常数值也不是完全在我脑海中的坏事(我记得在一些数字食谱书中看到它) ),但这只是一种强健的创可贴,通常会隐藏更严重的错误。
abs(1 - 3)*100 == 200
不是;因此,由于那些讨厌的极点妨碍了收敛,因此无法保证收敛。您希望查找根目录的功能是tan(x)
。该函数的定点迭代器将是f(x) = 3*x*tan(x)-1
或x = 1/(3*tan(x))
,它正在寻找x = 1/3*cot(x)
和3*tan(x)
的交集。但是,由于点数(2),这些迭代器仍然表现不好,因为它们是不连续的。
稍微不同的迭代器1/x
应该表现得更好,因为x = atan(1/(3*x))
的小值将产生有限值,因为x
沿着整个实线是连续的。唯一的缺点是atan(x)
的域限于间隔(-pi / 2,pi / 2),但如果它收敛,我认为限制是值得的。
最后,对于任何类似的未来编码工作,我强烈推荐@Adriaan的建议。如果想要在样式之间进行某种折衷,我的大部分迭代函数都是用这样的语义变量x
编写的:
notDone
你可以添加标志和所有爵士乐,但这种格式是我经常使用的。
答案 2 :(得分:0)
我相信使用牛顿方法进行收敛后,下面的代码可以实现您的目标。如果我错过了什么,请发表评论。
% find x: 3*x*tan(x) = 1
f = @(x) 3*x*tan(x)-1;
dfdx = @(x) 3*tan(x)+3*x*sec(x)^2;
tolerance = 0.05; % your value?
perturbation = 1e-2;
converged = 1;
x = 3.5;
f_x = f(x);
% Use Newton s method to find the root
count = 0;
err = 10*tolerance; % something bigger than tolerance to start
while (err >= tolerance)
count = count + 1;
if (count > 1e3)
converged = 0;
disp('Did not converge.');
break;
end
x0 = x;
dfdx_x = dfdx(x);
if (dfdx_x ~= 0)
% Avoid division by zero
f_x = f(x);
x = x - f_x/dfdx_x;
else
% Perturb x and go back to top of while loop
x = x + perturbation;
continue;
end
err = (abs((x - x0)/x))*100;
end
if (converged)
disp(['Converged to ' num2str(x,'%10.8e') ' in ' num2str(count) ...
' iterations.']);
end