C中的平方根算法

时间:2016-10-19 23:37:28

标签: c algorithm square-root

出于练习原因,我用C编写了以下算法:

#include <stdio.h>
#include <stdlib.h>


int main(){

double x=0;

printf("Enter the number: ");

scanf("%lf", &x);

int i = 0;

double v = 0;
double n=0;
int grenze = 12;
double z = 10;
/*
for(i=1; i<(x/2+1); i++){
    v=i;
    if((v*v) <= x){
        n = i;
    }
}

v=n;
*/
for(i=1; i<grenze+1; i++){
    z = z * 0.1;

    while(v*v<x){
        v = v + z;
        if(v*v<x){
            n = v;
        }
    }
    v=n;
}
printf("%.10f\n", n);



}

这很有效,但是对于大于某个值的数字(我不知道何时开始),例如50.000.000.000,该程序会冻结。

有什么我在这里看不到的吗?

2 个答案:

答案 0 :(得分:2)

对于足够大的数字v和足够小的数字zv = v + z;是无操作 - v不会改变。这使你的循环运行了很长时间。

算法不是一个好选择 - 您应该查找Newton-Raphson方法。我不相信你的算法适用于像1E-70这样的极端数字(并且你已经证明它对1E+70之类的数字不起作用)。请注意,在具有IEEE浮点支持的大多数机器上,双精度范围最高可达1E±300或更高。

  

你能解释一下为什么某个限制v = v + z是一个无操作者吗?

浮点数具有有限的十进制数字 - 通常为大约16左右。如果您添加1E+161E-16,则结果为1E+16;没有足够的有效数字来存储额外信息。您以5E+10为起点;您生成分数z = 1.0然后0.10.01,... 0.000 000 000 01或其左右(朋友之间的数量级是多少?)。当您添加最小值时,最终不会更改任何内容。

有关该主题的规范性文件为What Every Computer Scientist Should Know About Floating-Point Arithmetic或来自ACM

答案 1 :(得分:0)

如果你在while循环中写一个printf语句来向你展示v,你会看到它在某些时候停止变化(这很糟糕,因为你用它来退出你的循环! )。

我将printf("DEBUG: entered for loop, v=%lf\n", v);放入while循环中并看到了:

DEBUG: entered for loop, v=173205.080757
DEBUG: entered for loop, v=173205.080757
DEBUG: entered for loop, v=173205.080757
DEBUG: entered for loop, v=173205.080757
DEBUG: entered for loop, v=173205.080757
DEBUG: entered for loop, v=173205.080757
DEBUG: entered for loop, v=173205.080757
DEBUG: entered for loop, v=173205.080757

您添加的z非常小,当v为173205时,它实际上并未更改该值。您可以通过将v的类型更改为long double来扩展范围。但是,因为我们只有一定数量的位可以使用,所以仍然有一个上限,在其中添加足够小的数字不会改变可表示的值。