【发布时间】:2019-12-07 15:02:37
【问题描述】:
我正在做一个非常简单的 c 程序,它接收整数 n 并找到 n 的平方根近似值。
这是我的平方根近似函数,直到小数点后 5 位:
float sqrt_approx(int n){
float sqrt,how_many_tenths=10,how_many_decimals=0,i;
for (i=1;i<n;i++){
if ((i*i)<n) continue;
if (i*i==n){ sqrt=i; goto return_; }
else break;
}
sqrt=i-1;
for (i=0;i<10;i++){
if (i==9){
sqrt=sqrt+i/how_many_tenths;
how_many_tenths*=10;
how_many_decimals++;
if (how_many_decimals != 5) i=0;
else break;
}
if ((sqrt+i/how_many_tenths)*(sqrt+i/how_many_tenths) < n) continue;
sqrt=sqrt+(i-1)/how_many_tenths;
how_many_tenths*=10;
how_many_decimals++;
if (how_many_decimals != 5) i=0;
else break;
}
return_:
return sqrt;
}
蛮力,我会说非常直观。但是,当我试图将近似值精确到小数点后 6 位时,就会出现问题。为了做到这一点,我需要做的就是改变这个:
if (how_many_decimals != 5)
进入:
if (how_many_decimals != 6)
两次都在我的代码中。如果我要计算 35 美元的平方根近似值到小数点后 6 位, 我得到 5.916080 美元而不是 5.916079 美元。
我试图找出错误,在我看来,小数点后第 5 位被四舍五入了。看一下,我只更改了一点代码来了解这里发生了什么:
float sqrt_approx(int n){
float sqrt,how_many_tenths=10,how_many_decimals=0,i;
for (i=1;i<n;i++){
if ((i*i)<n) continue;
if (i*i==n){ sqrt=i; goto return_; }
else break;
}
sqrt=i-1;
for (i=0;i<10;i++){
if (i==9){
printf("%f + %f equals: ",sqrt,i/how_many_tenths); //NEW
sqrt=sqrt+i/how_many_tenths; //NEW
printf("%f\n",sqrt); //NEW
how_many_tenths*=10;
how_many_decimals++;
if (how_many_decimals != 6) i=0; //NEW (6 instead of 5)
else break;
}
if ((sqrt+i/how_many_tenths)*(sqrt+i/how_many_tenths) < n) continue;
sqrt=sqrt+(i-1)/how_many_tenths;
how_many_tenths*=10;
how_many_decimals++;
if (how_many_decimals != 6) i=0; //NEW (6 instead of 5)
else break;
}
return_:
return sqrt;
}
结果(输入printf("%f,sqrt_approx(35)后):
$5.000000 + 0.900000$ 等于:$5.900000$(这很好)
$5.916070+0.000009$ 等于:$5.916080$(这不好)
$5.916080$
这里似乎有什么问题?
【问题讨论】:
-
浮点值不够密集,无法获得超过 6 位小数的良好精度
-
不要使用
float;使用double。单精度浮点精度不足以使其可靠工作。 -
修复了它。赞赏。
-
35 的平方根是 5.91607978309961604256... 5.916080 是正确的近似值。 5.916079 完全错误。
-
35 的平方根不是 5.91607900000010001。如果您想近似 5.91607900000010001,请说出来,最好在一个单独的问题中使用尝试这样做的代码。
标签: c square-root