sqrt(1.0 - pow(1.0,2))返回-nan

Iva*_*van 2 c++

我发现了一个有趣的浮点问题.我必须在我的代码中计算几个平方根,表达式如下:

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)

Tro*_*nic 8

当你在循环中继续增加pos时,舍入错误会累积,在你的情况下,最终值> 1.0.取而代之的是,通过每轮的乘法计算pos,以获得最小量的舍入误差.

  • 即使有乘法,仍然存在1 - pow(1,2)将为负的风险. (2认同)

Ale*_* C. 5

问题在于浮点计算并不精确,并且 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)