[英]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) >= pontossag
為abszolut (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.