服用1.0f或-1.0f的acos是合法的吗?

时间:2011-12-13 13:09:22

标签: c++ math

我的代码出了问题,代理商四处走动突然消失了。这似乎是因为它们的位置在x和y轴上突然变为1.#INF000。我做了一点研究,有人说如果一个值分别超过或低于1和-1,这可能会发生在acos上,但接着说如果值也很接近就会发生这种情况。我添加了一个if语句来检查我是否曾经使用1或-1的acos并且它确实在它们消失之前评估为1个帧周期,但是我真的不明白能够修复它的问题。任何人都可以对这件事情有所了解吗?

D3DXVECTOR3 D3DXVECTOR3Helper::RotToTarget2DPlane(D3DXVECTOR3 position, D3DXVECTOR3 target)//XY PLANE
{
    //Create std::vector to target
    D3DXVECTOR3 vectorToTarget = target - position;

    D3DXVec3Normalize(&vectorToTarget, &vectorToTarget);

    //creates a displacement std::vector of relative 0, 0, 0
    D3DXVECTOR3 neutralDirectionalVector = D3DXVECTOR3(1, 0, 0);//set this to whatever direction your models are loaded facing   

    //Create the angle between them

    if(D3DXVec3Dot(&vectorToTarget, &neutralDirectionalVector) >= 1.0f ||D3DXVec3Dot(&vectorToTarget, &neutralDirectionalVector) <= -1.0f)
    {
        float i = D3DXVec3Dot(&vectorToTarget, &neutralDirectionalVector);
        float j = 0; //ADDED THIS IF STATEMENT
    }

    float angle = acos(D3DXVec3Dot(&vectorToTarget, &neutralDirectionalVector));

    if (target.y > position.y)
    {
        return D3DXVECTOR3(0, 0, angle);
    }
    else
    {
        return D3DXVECTOR3(0, 0, -angle);
    }
}//end VecRotateToTarget2DPlane()

2 个答案:

答案 0 :(得分:17)

对可能正好acos的值调用+/-1.0是危险的,因为舍入错误会导致计算值超出此范围。

但它很容易修复 - 改为使用此功能:

double SafeAcos (double x)
  {
  if (x < -1.0) x = -1.0 ;
  else if (x > 1.0) x = 1.0 ;
  return acos (x) ;
  }

答案 1 :(得分:5)

man page for acos告诉我们:

  

成功时,这些函数以弧度为单位返回x的反余弦值;该   返回值在[0,pi]范围内。

     

如果x是NaN,则返回NaN。

     

如果x为+1,则返回+0。

     

如果x为正无穷大或负无穷大,则会发生域错误,   然后返回NaN。

     

如果x超出范围[-1,1],则发生域错误,并且NaN为   返回。

这意味着对于[-1,+ 1]范围之外的值,该值不是数字。这也与the acos的定义方式相对应。