ArcTan2 (n, m)의 편의없이 Arctan을 어떻게 다루고 (0을 제로로 삼키지 않음) 어떻게 사용할 수 있습니까?

StackOverflow https://stackoverflow.com/questions/639283

문제

나는 한 지점에서 각도를 결정하려고 노력합니다 (n,m) 에게 (0,0). 없이 arctan2 가능하면 문제가 발생합니다 m 0이 될 수 있으며, 이는 0으로 가능한 분열로 이어집니다.

이 문제를 해결하기위한 우아하고 정확한 솔루션은 무엇입니까?

도움이 되었습니까?

해결책

기존 사분면을 사용하지 말고, 선 Y = +/- X로 정의 된 분기점을 사용하고, 코디 같은 알고리즘의 첫 번째 두 단계를 사용하십시오 (예 : 알려진 각도로 좌표를 회전하고 얼마나 많은 양을 추적하십시오. 've 회전) : :

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보다 큰 비율보다 y/x의 비율에 대해 정확할 가능성이 높기 때문입니다. 상호 복용)

다른 팁

ATAN2를 사용할 수없는 경우 제로 조건으로 나누기와 코드의 다른 모든 특수 사례를 확인해야합니다. 쉽게. ATAN2의 Wikipedia 항목에는 필요한 모든 조건이 있습니다.

대상 하드웨어를 지원하는 경우 부동 소수점 작업에 대한 예외 예외로 나뉩니다. 다른 옵션이 있습니다.

예외 원인을 점검하고 Atan 부서가 된 경우 문제를 해결하는 저수준 처리기를 설치하십시오. 예외가 드물면 ATAN2가 더 빨라지지만 낮은 레벨 링크가 필요하며 휴대용이 필요하지 않습니다.

표준을 구현하십시오 arctan(n, m) ArcTan을 컴퓨팅하기 전에 Taylor 시리즈를 사용하고 다음을 수행합니다.

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

또 다른 몇 가지 트릭 :

1) if |m| < |n|, 스왑 m, n 그런 다음 Arctan을 계산합니다. 마지막으로 결과를 빼십시오 Pi/2

2) if |m| 가까이 있습니다 |n|, 반 각도 공식을 사용하여 반 각도의 ArcTan 계산arctan(x) = 2*arctan(x/(1+sqrt(1+x*x))), 그렇지 않으면 그러한 값에 대해 Arctan은 매우 천천히 수렴합니다.

버전을 정의하십시오 arctan2. 매크로로서 C의 예 :

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

물론, 당신은 징후에 따라 사분면을 찾는 데 대해 자세히 설명 할 수 있습니다 n 그리고 m.

나는 이것이 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);
        }
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top