Cum ar trebui să abordeze arctan (și pentru a preveni deviding de la zero), fără a beneficia de ARCTAN2 (n, m) fiind disponibile?

voturi
4

Încerc să determine unghiul de la un punct (n,m)la (0,0). Fără a arctan2fi disponibile, Alerg în problema care mpoate fi 0, ceea ce conduce la o posibilă diviziune de la zero.

Care ar fi o soluție elegantă, corectă pentru abordarea acestei probleme?

Întrebat 12/03/2009 la 14:56
sursa de către utilizator
În alte limbi...                            


5 răspunsuri

voturi
0

Definiți versiunea de arctan2. Un exemplu în C ca macro:

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

Desigur, puteți elabora pentru identificarea cadranului in functie de semnele nsi m.

Publicat 12/03/2009 la 15:09
sursa de către utilizator

voturi
1

Dacă ATAN2 nu este disponibil, trebuie să verificați decalajul de starea zero și toate celelalte cazuri speciale în codul. Simplu. Intrarea pe wikipedia ATAN2 dispune de toate condițiile de care aveți nevoie.

Dacă hardware-ul țintă suportă divizare cu zero, excepții pentru operațiunile cu virgulă mobilă aveți o altă opțiune:

Instalați un manipulator de nivel scăzut, care verifică cauza excepție și în cazul în care happends să fie o divizie atan rezolva problema. Acest lucru va face ATAN2 mai repede în cazul în care sunt rare excepții, dar necesită meșterire nivel scăzut și nu este portabil.

Publicat 12/03/2009 la 15:13
sursa de către utilizator

voturi
0

Cred că acest lucru este o implementare corectă a ATAN2 folosind atan (nu se ocupa cu infinitati, deși):

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);
    }
}

ham de încercare:

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);
        }
    }
}
Publicat 12/03/2009 la 15:24
sursa de către utilizator

voturi
2

nu folosesc cadranele convenționale, utilizați punctele de ramificație definite de liniile y = +/- x, și utilizați 1st două etape ale unui algoritm CORDIC cum ar fi (de exemplu, coordonatele se rotesc cu un unghi cunoscut și de a urmări cât de mult vă „ve rotit):

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
}

motivul pentru care o fac în acest fel este faptul că atan () poate fi mai probabil să fie corecte pentru rapoarte y / x între -1 și +1, decât pentru rate mai mari decât 1. (deși un bun atan () algoritm ar recunoaște acest lucru și ia reciproca)

Publicat 12/03/2009 la 15:43
sursa de către utilizator

voturi
1

Punerea în aplicare a standardului arctan(n, m)folosind seria Taylor și de a face următoarele înainte de a calcula arctan:

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

Alte câteva trucuri:

1) în cazul în care |m| < |n|, de swap m, nși apoi calcula arctan. În cele din urmă scade rezultatul de laPi/2

2) în cazul în care |m|este aproape |n|, calcula arctan jumătății unghiului folosind jumătate formula unghi arctan(x) = 2*arctan(x/(1+sqrt(1+x*x))), în caz contrar, pentru astfel de valori, arctan converge foarte lent

Publicat 25/01/2010 la 08:46
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more