MatLab使用Fixed Point方法查找根

时间:2016-03-29 16:35:33

标签: matlab

我想为以下函数找到一个根,误差小于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我不知道为什么。

3 个答案:

答案 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)

我认为我将分别讨论四个问题:

  1. 为什么错误看似在200.0饱和并且循环无限延续?

    定义迭代器,如代码中所写,正在寻找f(x) = x - tan(x)/3的根;换句话说,找到xx的图形交叉的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

    除零和相对数量级是有时最好查看的绝对相对错误度量值的原因。自变量和函数值。如果需要的话,即使在相对计算的分母中放置一个极其(相对)小的有限,常数值也不是完全在我脑海中的坏事(我记得在一些数字食谱书中看到它) ),但这只是一种强健的创可贴,通常会隐藏更严重的错误。

    1. 与Newton-Raphson迭代相比,这种收敛性大不相同,因为它完全不知道斜率,并且定点迭代将收敛到固定点所在的位置(原谅次要重言式),假设它确实收敛。不幸的是,如果我没记错的话,只有当函数在某种程度上是连续的时才能保证定点收敛,abs(1 - 3)*100 == 200不是;因此,由于那些讨厌的极点妨碍了收敛,因此无法保证收敛。
      1. 您希望查找根目录的功能是tan(x)。该函数的定点迭代器将是f(x) = 3*x*tan(x)-1x = 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),但如果它收敛,我认为限制是值得的。

        1. 最后,对于任何类似的未来编码工作,我强烈推荐@Adriaan的建议。如果想要在样式之间进行某种折衷,我的大部分迭代函数都是用这样的语义变量x编写的:

          notDone
        2. 你可以添加标志和所有爵士乐,但这种格式是我经常使用的。

答案 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