我发现了一个有趣的浮点问题.我必须在我的代码中计算几个平方根,表达式如下:
sqrt(1.0 - pow(pos,2))
Run Code Online (Sandbox Code Playgroud)
其中pos在循环中从-1.0到1.0.-1.0对于pow来说很好,但是当pos = 1.0时,我得到了一个-nan.做一些测试,使用gcc 4.4.5和icc 12.0,输出
1.0 - pow(pos,2) = -1.33226763e-15
Run Code Online (Sandbox Code Playgroud)
和
1.0 - pow(1.0,2) = 0
Run Code Online (Sandbox Code Playgroud)
要么
poss = 1.0
1.0 - pow(poss,2) = 0
Run Code Online (Sandbox Code Playgroud)
显而易见,第一个会出现问题,而是消极的.任何人都知道为什么pow返回的数字小于0?完整的违规代码如下:
int main() {
double n_max = 10;
double a = -1.0;
double b = 1.0;
int divisions = int(5 * n_max);
assert (!(b == a));
double interval = b - a;
double delta_theta = interval / divisions;
double delta_thetaover2 = delta_theta / 2.0;
double pos = a;
//for (int i = 0; i < divisions - 1; i++) {
for (int i = 0; i < divisions+1; i++) {
cout<<sqrt(1.0 - pow(pos, 2)) <<setw(20)<<pos<<endl;
if(isnan(sqrt(1.0 - pow(pos, 2)))){
cout<<"Danger Will Robinson!"<<endl;
cout<< sqrt(1.0 - pow(pos,2))<<endl;
cout<<"pos "<<setprecision(9)<<pos<<endl;
cout<<"pow(pos,2) "<<setprecision(9)<<pow(pos, 2)<<endl;
cout<<"delta_theta "<<delta_theta<<endl;
cout<<"1 - pow "<< 1.0 - pow(pos,2)<<endl;
double poss = 1.0;
cout<<"1- poss "<<1.0 - pow(poss,2)<<endl;
}
pos += delta_theta;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当你在循环中继续增加pos时,舍入错误会累积,在你的情况下,最终值> 1.0.取而代之的是,通过每轮的乘法计算pos,以获得最小量的舍入误差.
问题在于浮点计算并不精确,并且 1 - 1^2 可能会给出较小的负结果,从而产生无效的sqrt计算。
考虑限制你的结果:
double x = 1. - pow(pos, 2.);
result = sqrt(x < 0 ? 0 : x);
Run Code Online (Sandbox Code Playgroud)
或者
result = sqrt(abs(x) < 1e-12 ? 0 : x);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5312 次 |
| 最近记录: |