在 c 中四舍五入小数错误?
Rounding up decimals bug in c?
我正在做一个非常简单的 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$
这里似乎有什么问题?
将 float 更改为 double 修复了它。谢谢大家的评论。
我正在做一个非常简单的 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$
这里似乎有什么问题?
将 float 更改为 double 修复了它。谢谢大家的评论。