4

我试图确定从一点(n,m)到的角度(0,0)。在没有arctan2可用的情况下,我m遇到了可能为 0 的问题,这导致可能被零除。

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

4

5 回答 5

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() 算法会认识到这一点并且取倒数)

于 2009-03-12T16:43:16.270 回答
1

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

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

安装一个低级处理程序来检查异常原因,如果它碰巧是一个 atan 部门,请修复问题。如果异常很少,这将使您的 atan2 更快,但它需要低级别的修补并且不可移植。

于 2009-03-12T16:13:50.893 回答
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(x) = 2*arctan(x/(1+sqrt(1+x*x))),否则,对于这样的值,反正切收敛非常慢

于 2010-01-25T09:46:25.850 回答
0

定义您的arctan2. C 中作为宏的示例:

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

当然,您可以详细说明根据 和 的符号找到n象限m

于 2009-03-12T16:09:23.790 回答
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);
        }
    }
}
于 2009-03-12T16:24:25.767 回答