如果没有ARCTAN2(n,m)的便利,我应该如何处理ARCTAN(并防止除以零)?

时间:2009-03-12 15:56:56

标签: math trigonometry divide-by-zero

我尝试确定从(n,m)(0,0)的角度。如果没有arctan2可用,我遇到m可能为0的问题,这可能导致可能被零除。

解决这个问题的优雅,正确的解决方案是什么?

5 个答案:

答案 0 :(得分:2)

不要使用常规象限,使用由线y = +/- x定义的分支点,并使用CORDIC类算法的前两个步骤(例如,按已知角度旋转坐标并跟踪你旋转了多少):

function atan2_substitute(x,y)
{
   double angle = 0;
   if (x < y)
   { angle = M_PI; x = -x; y = -y; }
   // this guarantees that the angle is between -135 and +45 degrees

   if (x < -y)
   {
     angle -= M_PI/2; tmp = x; x = -y; y = tmp;
   }
   // this guarantees that the angle is between -45 and +45

   angle += atan(y/x);

   if (angle > M_PI)
      angle -= 2*M_PI;
   // fails at 0,0; otherwise is accurate over the entire plane
}

这样做的原因是atan()可能更准确地适用于-1和+1之间的比率y / x,而不是大于1的比率。(尽管一个好的atan()算法会认识到这一点,并采取倒数)

答案 1 :(得分:1)

如果atan2不可用,您必须检查除零条件和代码中的所有其他特殊情况。很简单。 atan2上的维基百科条目具有您需要的所有条件。

如果您的目标硬件支持浮点运算的除零异常,您还有另一种选择:

安装一个检查异常原因的低级处理程序,如果它发生了atan分区则修复了这个问题。如果异常很少,这将使您的atan2更快,但它需要低水平的修补并且不可移植。

答案 2 :(得分:1)

使用Taylor系列实现标准arctan(n, m)并在计算arctan之前执行以下操作:

if (m == 0) {
    if (n < 0) return Pi;
    return 0;
}

另外几招:

1)如果|m| < |n|,则交换m, n,然后计算arctan。最后从Pi/2

中减去结果

2)如果|m|接近|n|,则使用半角公式计算半角的arctan arctan(x) = 2*arctan(x/(1+sqrt(1+x*x))),否则,对于这些值,arctan收敛非常缓慢

答案 3 :(得分:0)

定义arctan2的版本。 C中作为宏的一个例子:

#define atan2(n,m)   (m)==0 ? M_PI_2 : atan((n)/(m))

当然,您可以根据nm的符号详细说明找到象限。

答案 4 :(得分:0)

我相信这是使用atan的atan2的正确实现(但不处理无穷大):

float my_atan2(float y, float x)
{
    if(x == 0) // might also want to use fabs(x) < 1e-6 or something like that
    {
        if(y > 0)
            return M_PI_2;
        else
            return -M_PI_2;
    }
    else if(x > 0)
    {
        return atan(y/x);
    }
    else 
    {
        // x < 0                                                                                
        if(y > 0)
            return M_PI + atan(y/x);
        else
            return -M_PI + atan(y/x);
    }
}

测试工具:

int main()
{
    for(int i = -360; i <= 360; i++)
    {
        float x = cos(i / 180.0 * M_PI);
        float y = sin(i / 180.0 * M_PI);


        float good = atan2(y, x);
        float mine = my_atan2(y, x);


        if(fabs(good - mine) > 1e-6)
        {
            printf("%d %f %f %f %f\n", i, x, y, good, mine);
        }
    }
}