Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 迭代停留在16512次迭代时,预计进行100000次迭代_C - Fatal编程技术网

C 迭代停留在16512次迭代时,预计进行100000次迭代

C 迭代停留在16512次迭代时,预计进行100000次迭代,c,C,我非常震惊,为什么我的代码在16512次迭代时被卡住了,尽管它似乎没有语法问题。代码如下: #include <stdio.h> /*C version of Newton-Raphson method*/ float sqrt(float num); main() { int i; for (i = 1; i <= 100000; i++) { printf("%d: %.3f\n", i, sqrt(i)); } } float

我非常震惊,为什么我的代码在16512次迭代时被卡住了,尽管它似乎没有语法问题。代码如下:

#include <stdio.h>
/*C version of Newton-Raphson method*/
float sqrt(float num);

main() 
{
    int i;
    for (i = 1; i <= 100000; i++) {
        printf("%d: %.3f\n", i, sqrt(i));
    }
}

float sqrt(float num)

{
    float guess, e, upperbound;
    guess = 1;
    e = 0.001;
    do 
    {
        upperbound = num / guess;
        guess = (upperbound + guess) / 2;
    } while (!(guess * guess >= num - e && 
               guess * guess <= num + e));
    return guess;
}
#包括
/*Newton-Raphson方法的C版本*/
浮点sqrt(浮点数);
main()
{
int i;
对于(i=1;i=num-e&&

guess*guess老实说,当我发布mycomment时,这更多的是一种直觉,而不是真实的知识。该算法是有效的,因此一定有什么东西使while循环不会终止,而且由于您正确地使用了ε,我们已经达到了浮点的极限

@PaulR的评论让它更有意义。16512的sqrt是128.499027233672…浮点的精度相当有限,所以它在该数字的0.001范围内没有得到任何东西。如果你想一个更大的数字,它更有意义,例如sqrt(123455555.54321)(即11111.11111).浮点精度甚至不一定能达到11111,更不用说11111.111了

更改为双重“修复”这一点,但只是在路上踢了一脚。以后的某个时候,我们会遇到同样的精度问题,该算法应该适用于任何大小的数字

@Bratch先生提出了一个稳健的解决方案——将公差定义为数字的百分比。如果设置
e=num*0.00001
,循环将始终完成。显然,您可以使用epsilon并对其进行调整,以达到满意的效果。请注意,对于大数字,这会给出一个整数,它甚至不是最接近右边的整数回答


我不能代表python发言,但我可以证实这一点。

正如在评论中已经解释的,问题是您不能有那么高的精度(0.001)任何数字。特别是当数字足够大时,只保存最重要的数字。如果您想了解有关其工作原理的更多信息,请参阅IEEE 754标准

现在,我建议您使用误差百分比作为公差:

float sqrt(float num)

{
    float guess, e, upperbound;
    guess = 1;
    e = 0.001;
    do 
    {
        upperbound = num / guess;
        guess = (upperbound + guess) / 2;
    } while (!(guess * guess / num >= 1 - e && 
               guess * guess / num <= 1 + e));
    return guess;
}
float sqrt(float num)
{
浮点猜测,e,上界;
猜测=1;
e=0.001;
做
{
上限=num/猜测;
猜测=(上限+猜测)/2;
}而(!(guess*guess/num>=1-e&&

guess*guess/numIMHO,平方会导致精度损失:

#include <stdio.h>
/*C version of Newton-Raphson method*/
float mysqrt(float num); /* avoid conflicts with built-in sqrt() if any */

int main(void)
{
    int i;
    for (i = 1; i <= 100000; i++) {
        printf("%d: %.3f\n", i, (double)mysqrt(i)); /* cast to double, since printf() is varargs */
    }
return 0;
}


float mysqrt(float num)
{
    float newguess, e, oldguess;
    e = 0.001;
    newguess = 1.0;
    do
    {
        oldguess = newguess;
        newguess = (num/oldguess + newguess ) / 2;
        /* compare tor the previous value; avoid squaring */
    } while (newguess / oldguess > (1+e) || oldguess / newguess > (1+e) );
    // } while (newguess < oldguess -e || newguess > oldguess +e); // "mostly works"
    return newguess;
}
#包括
/*Newton-Raphson方法的C版本*/
float mysqrt(float num);/*避免与内置sqrt()冲突(如果有)*/
内部主(空)
{
int i;
对于(i=1;i(1+e)| oldguess/newguess>(1+e));
//}while(newguessoldguess+e);/“大部分有效”
返回newguess;
}

简单调整

使用相对浮点精度,而不是绝对精度

在0.001和0.002之间的FP表示数与1000和2000之间的FP表示数一样多。因此,在计算平方根时,迭代应取决于局部相对误差

不要使用绝对误差范围,比如
e=0.001
,而是使用相对误差范围。这样代码就可以正常运行了

// e = 0.001;
e = 0.001 * num;


[编辑]我知道see@Scott Mermelstein也有类似的评论。

我希望如果你将
浮点
s改为
double
s,问题会自行解决……你的错误是对
e
使用固定公差,并假设
浮点
s具有无限精度。@PaulR是正确的。对于
浮点
你没有e对于太大的数字,期望的精度为
0.001
公差。您可以使用
double
增加最大有效位数,或者将公差定义为原始数字的一小部分。
float
可以“保持”+-10E37,但这并不意味着你能把有效数字降到1位数,更不用说千分之十的小数位数了。你需要考虑有意义的数字。一个<代码>双< /代码>会给你更多的有效数字,并增加你的算法最大的数值。一般来说,你应该试着做。问问题时,你的代码看起来尽可能好。花时间去除明显的瑕疵是值得的,即使是像一个无害的零散分号这样的小瑕疵也是值得的。很难确定你是否知道这很奇怪,所以人们会指出你代码中的奇怪之处。仅供参考,双精度有15-17个有效进动数字。因此,如果您尝试查找sqrt(12345678901234567^2),几乎肯定会失败。(在其中的任何位置放置一个小数位,您都会遇到相同的问题。)
(double)
不需要,因为
float
printf()的参数
已升级为
double
。这是正确的。我仍然对vararg函数非常谨慎,即使给定默认类型升级。