我是这个话题的初学者,并且找不到原因:有时程序有效,有时候没有(在提出问题之后,它根本不想接受我的答案,而不是我能写下我想要的,它没有回应,只列出数字,我插入)
#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;
}
答案 0 :(得分:1)
abszolut (tipp*tipp-szam) >= pontossag*szam
tipp*tipp
接近szam
时,必须停止while循环。但IEEE floating point computations的精确度有限: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
,精度为无量纲。比较具有相同维度的事物是一种很好的做法。
如果您注意到无限循环,请切换到双精度或增加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
解析该行。