Newton Raphson迭代陷入无限循环

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

#include  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 = 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

一旦tipp*tipp接近szam ,while循环必须停止。 但IEEE浮点计算的精度有限: float大约为7位, double精度位数为15位。

所以float szam的错误float szam0.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

为了避免无限循环,添加一个计数器int i; 如果迭代次数为100,则退出while循环.100应该足够了,因为Newton-Raphson迭代具有二次收敛。

您的代码存在许多问题。

循环中的退出条件存在缺陷。
平方根算法的问题是使用误差限制pontossag。 您的算法将为非常小的数字提供错误的结果,并且对于大于20的数字,它将永远循环。 要解决此问题,请将循环测试从abszolut (tipp*tipp-szam) >= pontossagabszolut (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系列function的状态,以查看扫描仪是否扫描了预期的项目数。

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