Newton Raphson迭代陷入无限循环

时间:2015-02-28 12:05:04

标签: c floating-point-precision newtons-method

我是这个话题的初学者,并且找不到原因:有时程序有效,有时候没有(在提出问题之后,它根本不想接受我的答案,而不是我能写下我想要的,它没有回应,只列出数字,我插入)

  #include <stdio.h>

float abszolut (float szam)
{
    float abszoluterteke;
    if (szam >=0)
         abszoluterteke = szam;
    else 
        abszoluterteke = -szam;
    return abszoluterteke;
}

float negyzetgyok (float szam)
{
    float pontossag = 0.000001;
    float tipp = 1;
    if (szam <0)
    {
        printf ("Megszakítás elfogadva! \nKöszönjük, hogy programunkat választotta!\n");
        return -1;
    }
    else
        {while (abszolut (tipp*tipp-szam) >= pontossag)
            tipp = (szam/tipp + tipp)/2;
        return tipp;
    }
}

int main (void)
{
    float alap, eredmeny;
    for (;;)
    {
        printf ("Melyik számnak szeretnéd meghatározni a négyzetgyökét ilyen módszerrel?\n");
        scanf ("%f", &alap);
        eredmeny = negyzetgyok (alap);
        if (eredmeny == -1)
            return 1;
        else
         printf ("A(z) %f négyzetgyöke megfelelő közelítéssel: %f\n", alap, eredmeny);




    }
    return 0;
}

2 个答案:

答案 0 :(得分:1)

abszolut (tipp*tipp-szam) >= pontossag*szam

的更改

tipp*tipp接近szam时,必须停止while循环。但IEEE floating point computations的精确度有限:float约为7位,double约为15位。

因此float szam上的错误大约是0.0000001*szamtipp的情况相同。因此,tipp*tipp-szam上的错误高于0.0000001*szam。如果szam很大,则此错误几乎不会低于0.000001即使使用double精度,while (abszolut (tipp*tipp-szam) >= pontossag)很可能会触发非常大数字的无限循环。

另一方面,如果szam非常小,会发生什么?比如1e-10 while循环过早退出,1e-10的平方根计算为关于1e-3的内容,而不是1e-5 ... 相对错误大约为10000%...使用double不会改变任何内容!

要避免这种情况,您可以更改abszolut (tipp*tipp-szam) >= pontossag*szam

请注意,双方都有相同的尺寸。如果szam的平方英尺为tipp,则pontossag为英尺,pontossag,精度为无量纲。比较具有相同维度的事物是一种很好的做法。

如果您注意到无限循环,请切换到双精度或增加int i;

要避免无限循环,请添加计数器{{1}},如果迭代次数为100,则退出while循环.100应该足够了,因为Newton-Raphson iteration具有二次收敛。

答案 1 :(得分:0)

您的代码存在许多问题。

循环中的退出条件存在缺陷。
平方根算法的问题是使用错误限制pontossag。您的算法将为非常小的数字提供错误的结果,并且对于大于20的数字,它将永远循环。要解决此问题,请将循环测试从abszolut (tipp*tipp-szam) >= pontossag更改为abszolut (tipp*tipp-szam) >= pontossag*szam

您没有检查所有问题情况。
如果您的计算机使用IEEE 754浮点,您的算法就会起作用。那只是运气。在进行数值编程时,不要依赖运气。输入无穷大很容易。例如,3.5e38(350000000000000000000000000000000000000)可以使用单精度数字(float)。您的函数negyzetgyok应检查无穷大:

if (isinf (szam))
{
    return szam;
}

你可以比平方根的初始猜测1.0做得更好。
初始猜测1.0对3.4e38意味着很多不必要的循环。形成良好初始猜测的快速简便方法是利用浮点数在内部表示为(1+fractional_part)*2^exponent的事实。一个好的第一个猜测是1*2^(exponent/2)。使用单精度数字

int expo;
float tipp;
frexpf (szam, &expo);
tipp = ldexpf (1.0f, n/2);

您正在使用%f而不是%g来解析浮点数。
%g格式可以解析任何可以使用%f格式解析的内容,还有更多内容。

您没有检查fscanf的状态 提示输入数字时输入x。扫描仪将读取该字符,从而停止扫描。扫描程序将该字符(x)放回输入缓冲区,并返回0,表示没有扫描任何内容。下一次,扫描仪将再次读取字符x,再次将该字符放回输入缓冲区,再次返回0.无限循环!始终检查任何scanf系列功能的状态,以查看扫描仪是否扫描了预期的项目数。

您正在使用fscanf
此站点上有许多现有问题和答案,解决了使用fscanf从文件中读取的许多问题。在阅读人为输入时尤其如此。人们会犯错误。忽略人们确实在输入数据时出错是编程错误。更好的方法是使用frets将行读入缓冲区并使用sscanf解析该行。