簡體   English   中英

牛頓拉夫森迭代陷入無限循環

[英]Newton Raphson iteration trapped in infinite loop

我是這個主題的初學者,無法找出原因:有時程序可以工作,有時不能(在問了問題之后,它根本不想接受我的答案,而我可以這樣寫:只要我想要,它就不會回應,只列出數字,我便提示了)

  #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;
}

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

while循環必須停止一次tipp*tipp接近szam 但是IEEE浮點數計算的精度有限: float約為7位, double精度數約為15位。

因此, float szam的錯誤約為0.0000001*szam tipp也是一樣。 因此, 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的精度是無量綱的。 比較具有相同維度的事物是一個好習慣。

如果您一直注意到無限循環,請切換為雙精度或增加pontossag

為了避免無限循環,請添加一個計數器int i; 如果迭代次數為100,則退出while循環。100應該足夠,因為您的Newton-Raphson迭代具有二次收斂性。

您的代碼有很多問題。

您循環中的退出條件有缺陷。
平方根算法的問題是使用了錯誤限制pontossag。 對於很小的數字,您的算法將給出錯誤的結果,並且對於大於20左右的數字,它將永遠循環。 要解決此問題,請將循環測試從abszolut (tipp*tipp-szam) >= pontossagabszolut (tipp*tipp-szam) >= pontossag*szam

您並沒有檢查所有問題案例。
如果您的計算機使用IEEE 754浮點,則您的算法可以正常工作。 真是運氣。 進行數值編程時,切勿依賴運氣。 輸入無窮大很容易。 例如,3.5e38(350000000000000000000000000000000000000000000)使用單精度數字( float )進行欺騙。 您的函數negyzetgyok應該檢查無窮大:

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

您可以做的比起最初的平方根1.0更好。
相對於3.4e38的1.0的初始猜測意味着很多不必要的循環。 形成良好的初始猜測的一種快速簡便的方法是利用以下事實:浮點數在內部表示為(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解析該行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM