두 각도의 가장 작은 차이


137

좌표 주위 -PI-> PI 범위에 2 개의 각도가 주어지면 두 각도 중 가장 작은 값은 무엇입니까?

PI와 -PI의 차이는 2 PI가 아니라 0입니다.

예:

중심에서 2 개의 선이 나오는 원을 상상해보십시오. 선 사이에 2 개의 각도가 있습니다. 내부 의 각도는 더 작은 각도 이고 외부의 각도는 더 큰 각도입니다. 합산하면 두 각도가 완전한 원을 만듭니다. 각 각도가 특정 범위 내에 들어갈 수 있다고 가정 하면 롤오버를 고려하여 작은 각도 값은 얼마입니까?


2
나는 당신이 무엇을 의미하는지 이해하기 전에 3 번 읽었습니다. 예를 추가하거나 더 잘 설명해주세요 ...
Kobi

중심에서 2 개의 선으로 시작하는 원을 상상해보십시오. 선 사이에 2 개의 각도가 있습니다. 내부의 각도는 더 작은 각도이고 외부의 각도는 더 큰 각도입니다. 합산하면 두 각도가 완전한 원을 만듭니다. 각각의 각도가 일정 범위 내에 들어갈 수있는 점을 감안, 계정에 롤오버 복용, 작은 각도 값 것입니다
톰 J 노웰을


2
@JimG. 이것은 같은 질문이 아닙니다.이 질문에서 다른 질문에 사용 된 각도 P1은 잘못된 답이 될 것이고 다른 작은 각도 일 것입니다. 또한, 각도가 수평 축과 일치한다는 보장이 없습니다
Tom J Nowell

답변:


193

이것은 모든 각도에 대해 서명 된 각도를 제공합니다.

a = targetA - sourceA
a = (a + 180) % 360 - 180

많은 언어에서 modulo오퍼레이션은 피제수와 동일한 부호를 가진 값을 리턴합니다 (예 : C, C ++, C #, JavaScript, 전체 목록 here ). 이를 위해서는 다음 mod과 같은 사용자 정의 기능 이 필요합니다 .

mod = (a, n) -> a - floor(a/n) * n

정도:

mod = (a, n) -> (a % n + n) % n

각도가 [-180, 180] 이내 인 경우에도 작동합니다.

a = targetA - sourceA
a += (a>180) ? -360 : (a<-180) ? 360 : 0

좀 더 장황한 방법으로 :

a = targetA - sourceA
a -= 360 if a > 180
a += 360 if a < -180

더 간단하고 더 큰 소리로 읽을 수 있습니다. 비록 사실상 같은 것을하더라도, 먼저 bti는 각도를 알아 내고, 두 번째 부분은 항상 가능한 두 가지 각도 중에서 더 작습니다
Tom J Nowell

1
비록 각도 0과 목표 각도 721을 가지고 있다면 % 360을하고 싶을 수도 있지만, 정답은 1이 될 것입니다. 위의 답변은 361입니다.
Tom J Nowell

1
후자의 접근법의 두 번째 진술과 동등한 잠재적으로 더 비싸지 만 더 간결한 것은 a -= 360*sgn(a)*(abs(a) > 180)입니다. (당신의 무점포 구현을 한 경우 그것을 생각 해 보 니, sgnabs특성 힘은 실제로 두 개의 곱셈을 필요로 보상하기 위해 시작하는 것이 다음.)
mmirate

1
"모든 각도의 부호있는 각도"예제는 대부분의 시나리오에서 한 가지 예외를 제외하고 작동하는 것 같습니다. 시나리오에서 double targetA = 2; double sourceA = 359;'a'는 3.0 대신 -357.0과 동일합니다.
Stevoisiak

3
C ++에서는 std :: fmod (a, 360) 또는 fmod (a, 360)을 사용하여 부동 소수점 모듈로를 사용할 수 있습니다.
Joeppie

145

x는 목표 각도입니다. y는 소스 또는 시작 각도입니다.

atan2(sin(x-y), cos(x-y))

부호있는 델타 각도를 반환합니다. API에 따라 atan2 () 함수의 매개 변수 순서가 다를 수 있습니다.


13
x-y각도 차이가 있지만 원하는 범위를 벗어날 수 있습니다. 이 각도가 단위 원의 점을 정의한다고 생각하십시오. 그 점의 좌표는입니다 (cos(x-y), sin(x-y)). 범위가 [-PI, PI] 인 경우를 제외하고 해당 atan2점에 대한 각도 (와 동일)를 반환합니다 x-y.
Max


2
한 줄 간단한 솔루션으로 나를 위해 해결되었습니다 (선택된 답변이 아닙니다.)). 그러나 tan inverse는 비용이 많이 드는 프로세스입니다.
Mohan Kumar

2
나에게 가장 우아한 해결책. 계산 비용이 많이들 수 있습니다.
focs

나에게도 가장 우아한 해결책! 내 문제를 완벽하게 해결했습니다 ( 두 가지 가능한 회전 방향 / 각도에서 작은 회전 각도를 서명 하는 수식을 원함).
위르겐 브라우어

41

두 각도가 x와 y 인 경우 두 각도 사이의 각도 중 하나는 abs (x-y)입니다. 다른 각도는 (2 * PI)-abs (x-y)입니다. 따라서 두 각도 중 가장 작은 값은 다음과 같습니다.

min((2 * PI) - abs(x - y), abs(x - y))

이는 각도의 절대 값을 제공하며 입력이 정규화되었다고 가정합니다 (예 : 범위 내 [0, 2π)).

각도의 부호 (예 : 방향)를 유지하고 범위 [0, 2π)를 벗어난 각도를 허용 하려면 위의 일반화 할 수 있습니다. 다음은 일반화 된 버전의 Python 코드입니다.

PI = math.pi
TAU = 2*PI
def smallestSignedAngleBetween(x, y):
    a = (x - y) % TAU
    b = (y - x) % TAU
    return -a if a < b else b

있습니다 %음의 값이 관여 할 때 운영자가 일부 기호 조정을 포팅하는 것이 필요할 수 있습니다 그렇다면, 특히, 모든 언어에서 동일하게 동작하지 않습니다.


1
@bradgonesurfing 그것은 사실이지만, 공정하게 테스트는 원래 질문에 명시되지 않은 것들, 특히 표준화되지 않은 입력과 부호 보존을 검사했습니다. 수정 된 답변의 두 번째 버전은 테스트를 통과해야합니다.
Laurence Gonsalves

두 번째 버전도 작동하지 않습니다. 예를 들어 350과 0을 시도하십시오. -10을 반환해야하지만 -350을 반환해야합니다
kjyv

@kjyv 나는 당신이 묘사하는 행동을 재현 할 수 없습니다. 정확한 코드를 게시 할 수 있습니까?
Laurence Gonsalves

아 죄송합니다. 파이썬에서 rad와 degree를 사용하여 버전을 정확하게 테스트했으며 정상적으로 작동했습니다. C #으로의 번역에서 실수 였을 것입니다 (더 이상은 없어야 함).
kjyv

2
파이썬 3부터는 실제로 타우를 기본적으로 사용할 수 있습니다! 그냥 쓰십시오 from math import tau.
mhartl

8

나는 서명 된 답변을 제공 해야하는 도전에 직면합니다.

def f(x,y):
  import math
  return min(y-x, y-x+2*math.pi, y-x-2*math.pi, key=abs)

1
아 ... 대답은 그건 그렇고 파이썬 함수입니다. 죄송합니다. 잠시 파이썬 모드에있었습니다. 괜찮습니다.
David Jones

새로운 공식을 위층의 코드에 연결하고 그 공식이 어떻게되는지 살펴 보겠습니다! (감사합니다 ^ _ ^)
Tom J Nowell

1
PeterB의 대답도 정확하다고 확신합니다. 그리고 악하게 해킹. :)
David Jones

4
그러나 이것은 삼각 함수를 포함하지 않습니다 :)
nornagon

Java의 동등한 공식은 무엇입니까? 각도가 정도라면?
Soley



2

모든 각도와 라디안 및 각도 모두에서 작동하는 C ++의 효율적인 코드는 다음과 같습니다.

inline double getAbsoluteDiff2Angles(const double x, const double y, const double c)
{
    // c can be PI (for radians) or 180.0 (for degrees);
    return c - fabs(fmod(fabs(x - y), 2*c) - c);
}

-1

삼각 함수를 계산할 필요가 없습니다. C 언어의 간단한 코드는 다음과 같습니다.

#include <math.h>
#define PIV2 M_PI+M_PI
#define C360 360.0000000000000000000
double difangrad(double x, double y)
{
double arg;

arg = fmod(y-x, PIV2);
if (arg < 0 )  arg  = arg + PIV2;
if (arg > M_PI) arg  = arg - PIV2;

return (-arg);
}
double difangdeg(double x, double y)
{
double arg;
arg = fmod(y-x, C360);
if (arg < 0 )  arg  = arg + C360;
if (arg > 180) arg  = arg - C360;
return (-arg);
}

라디안으로 dif = a-b하자

dif = difangrad(a,b);

dif = a-b, 각도로 보자

dif = difangdeg(a,b);

difangdeg(180.000000 , -180.000000) = 0.000000
difangdeg(-180.000000 , 180.000000) = -0.000000
difangdeg(359.000000 , 1.000000) = -2.000000
difangdeg(1.000000 , 359.000000) = 2.000000

죄도없고, cos도없고, 황갈색도 없습니다 .... 기하학 만 !!!!


7
곤충! PIV2를 "(M_PI + M_PI)"가 아닌 "M_PI + M_PI"로 # 정의하기 때문에 행이로 arg = arg - PIV2;확장되어 arg = arg - M_PI + M_PI아무 것도 수행하지 않습니다.
canton7
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.