2014-06-15 9 views
8

Czy istnieje funkcja biblioteczna lub znana, szybka i wydajna metoda w języku Java w celu znormalizowania kąta do +/- π - np. podczas dodawania dwóch kątów?Standardowy sposób normalizowania kąta do +/- π radianów w Javie

Co mam teraz (na podstawie this answer) jest w zasadzie poniżej kod ...

private static final double TWO_PI = 2 * Math.PI; 

double normalize(double theta) { 
    double normalized = theta % TWO_PI; 
    normalized = (normalized + TWO_PI) % TWO_PI; 
    return normalized <= Math.PI ? normalized : normalized - TWO_PI; 
} 

... ale wydaje się nieco skomplikowany i wydajność mądry nie jestem podekscytowani operator modulo. (Zauważ, że nie mogę zagwarantować, że theta nie jest dość dużą liczbą, więc nie sądzę, że istnieje czyste rozwiązanie dodawania/odejmowania bez pętli.Nie wiem dokładnie, w jaki sposób pętla ręcznie zwijana może być porównywana z %.)

Czy istnieje dobrze przetestowana zoptymalizowana funkcja biblioteki, której mogę użyć, lub lepszy algorytm, czy jest tak dobry, jak to tylko możliwe?

+0

Próbujesz zaokrąglić do najbliższego 90 stopni (połowa pi) lub najbliższego 180 stopni (pełne pi)? – Kon

+0

@Kon 180 stopni/pełne pi. –

+0

możliwy duplikat [Łatwy sposób na zachowanie kątów pomiędzy -179 a 180 stopniami] (http://stackoverflow.com/questions/2320986/easy-way-to-keeping-angles-między 179- i -180-degrees) –

Odpowiedz

12

Apache Commons ma jedno:

http://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/org/apache/commons/math3/util/MathUtils.html#normalizeAngle(double, double)

normalizować kąt między -π i + π

a = MathUtils.normalizeAngle(a, 0.0);

I patrząc na kod źródłowy, można odtworzyć to z tym (używają własnego FastMath.floor, ale w przypadku, gdy chcesz to zrobić bez wnętrzne biblioteka):

theta - TWO_PI * Math.floor((theta + Math.PI)/TWO_PI) 

źródłowy jest tutaj: https://github.com/apache/commons-math/blob/53ec46ba272e23c0c96ada42f26f4e70e96f3115/src/main/java/org/apache/commons/math4/util/MathUtils.java#L107


Uwaga dla czytelników z przyszłości: metoda ta ma tylko (czerwiec 2017) been removed z najnowszej 4.x Commons matematyki baza kodów. Jeśli używasz wersji po tym, będziemy chcieli użyć commons-numbers zamiast (raz to zwolniony) - obecnie:

a = PlaneAngleRadians.normalizeBetweenMinusPiAndPi(a); 

lub

a = PlaneAngleRadians.normalize(a, 0.0); 
4

Jest tylko jeden 100% niezawodny sposób:

public static double normalizeAngle(double angle) { 
    return Math.atan2(Math.sin(angle), Math.cos(angle)); 
} 

Cała reszta to ludzie, którzy chcą być zbyt sprytni i upadający.

+3

Ta metoda jest prawdopodobnie bardziej dokładna (i myślę, że zapewnia półzamknięty zakres, w przeciwieństwie do 'MathUtils'), ale jest także około 40x wolniejsza (mediana ~ 190ns na moim 15" MBP, vs. ~ 4.9ns przy użyciu 'MathUtils') , co może być ważniejsze w przypadku niektórych aplikacji. –

+0

Zgadzam się, atan2 może być powolny. Ale obsługuje przypadki z NaN i ± Infinity. – cohadar

+0

MathUtils również je obsługuje - zwraca NaN dla wszystkich trzech, tak jak atan2. –

Powiązane problemy