IDL/Programming

삼각함수의 사용에 있어서 유의할 점들

이상우_IDL 2013. 7. 4. 17:25
728x90

오늘은 IDL에서 삼각함수를 다루는데 있어서 우리가 유의를 하면 좋을만한 얘기들을 해보기로 하겠습니다. 타 프로그래밍 언어들과 마찬가지로 IDL에서도 SIN, COS, TAN 등의 삼각함수들이 지원됩니다. 가장 기본적인 유의사항은 이러한 삼각함수 연산을 위한 내장함수들의 인자는 각도(degree)가 아닌 라디안(radian) 값으로 주어져야 합니다. 예를 들어, 30도라는 각도에 대한 Sine 함수값을 구하려면, SIN(30)이 아니라 SIN(30*!DTOR)과 같이 각도 단위의 값을 라디안 값으로 변환해주는 !DTOR이라는 시스템 변수값을 사용하는 것이 바람직합니다. 참고로 !DTOR이란 이름은 'Degree TO Radian'이란 값을 가집니다. 반대로 라디안 값을 각도 단위의 값으로 변환해주는 역할을 하는 시스템 변수도 있는데, 이것은 이름이 !RADEG니다. 즉, 'RAdian to DEGree'라는 의미로 보면 됩니다.


IDL> PRINT, SIN(30*!DTOR)

     0.500000


그리고 SIN, COS, TAN의 역함수 역할을 하는 ASIN, ACOS, ATAN과 같은 내장함수들도 있습니다. 예를 들어, ASIN은 Sine 값 자체를 인자로 주고 그에 해당되는 각도 값을 돌려주는 역할을 하는 내장함수입니다. 즉 아래와 같이 사용하면 됩니다.


IDL>PRINT, ASIN(0.5)

0.523599


그런데 돌려받은 값이 약간 이상하죠? 물론 이러한 내장함수는 리턴값을 라디안으로 주게 되어 있습니다. 따라서 우리에게 익숙한 각도 단위의 값으로 변환하려면, 앞서 소개한 !RADEG를 다음과 같이 곱해주면 됩니다.


IDL> PRINT, ASIN(0.5)*!RADEG

      30.0000


특히 ASIN, ACOS과 같은 함수를 사용할 때 유의해야 할 사항은, 이 함수에 주어지는 인자의 값은 -1~+1의 범위내에 있어야 합니다. 이것은 뭐 당연히 Sine, Cosine 함수의 값이 가질 수 있는 범위가 -1~+1이기 때문입니다. 그런데, 코딩할 때 ASIN이나 ACOS의 함수를 사용하는데 있어서 인자를 변수로 주는 경우도 충분히 있을 수 있습니다. 예를 들면 다음과 같은 경우입니다.


IDL> result = ASIN(a/b)


즉, a의 값을 b로 나누고 그 결과값을 ASIN 함수의 인자로 사용하는 경우입니다. 물론 프로그램의 내용상 a/b가 항상 -1~+1의 범위를 벗어날 일이 전혀 없다면 별다른 문제는 없습니다. 그런데, 불가항력적인 이유로 인하여 a/b가 가끔은 이 범위를 약간 벗어나는 경우도 발생할 수 있습니다. 예를 들면, a는 1.01이고 b=1.0인 경우를 들 수 있습니다. 즉, a와 b가 일종의 측정값인데 약간의 오차로 인해서 이런 경우가 발생할 수도 있다라는 가정을 해보는 것입니다. 그러면 이 상태로 ASIN 계산을 해보면 다음과 같은 결과가 나오게 됩니다.


IDL> a = 1.01

IDL> b = 1.0

IDL> PRINT, ASIN(a/b)*!RADEG

     -NaN


NaN은 'Not A Number', 즉 정상적인 숫자값으로 정의될 수 없는 아무 의미없는 결과인 셈입니다. 이런 결과가 나오는 것은 뭐 당연합니다. ASIN 함수에 사용된 인자의 값이 1.01/1.0, 즉 1보다 약간이나마 큰 값이니까요. 하지만, 프로그램의 구동에 있어서 이렇게 분모가 분자보다 약간 벗어나는 경우에는 그냥 a/b를 유효범위의 최대값인 1로 간주해버리고 계산을 진행하도록 하는 것이 바람직할 경우도 있습니다. 이럴 경우에는 다음과 같이 해주면 됩니다.


IDL> a = 1.01

IDL> b = 1.0

IDL> PRINT, ASIN((a/b)<1)*!RADEG

     90.0000


여기서 ASIN에 들어간 인자의 내용을 보면, 기존에는 그냥 a/b였지만 지금은 (a/b)<1이라고 되어 있습니다. 즉, a/b의 값이 행여나 1을 넘어가는 경우라 하더라도 (a/b)<1은 무조건 1로 인식됩니다. 이미지 프로세싱에서도 사용되는 클리핑(Clipping) 기법을 그냥 단일값에 대하여 적용한 경우입니다. 같은 원리로, 유효범위의 최소값인 -1보다도 작아질 가능성이 보인다고 하면 다음과 같이 a/b의 하한값도 그냥 -1로 인식되도록 할 수 있습니다.


IDL> a = -1.01

IDL> b = 1.0

IDL> PRINT, ASIN((a/b)>(-1))*!RADEG

     -90.0000


괄호가 많이 나와서 약간 혼란스러울 가능성은 있지만, ASIN 함수의 인자의 내용을 보면 (a/b)>(-1)이라고 되어 있습니다. 즉, a/b가 -1보다 작아지는 경우에는 그냥 -1로 인식하라는 의미입니다. 그러면 유효범위의 상한 및 하한을 동시에 다음과 같이 한정짓는 것도 가능합니다.


IDL> a = 1.01

IDL> b = 1.0

IDL> PRINT, ASIN((a/b)>(-1)<1)*!RADEG

     90.0000


물론 이렇게 연산의 값을 일정 범위로 한정시켜버리는 것이 작업의 성격상 필요할 수도 있고, 그렇지 않은 경우도 있을 수 있습니다. 그 판단은 물론 프로그래머의 재량입니다. 어쨌든 프로그램의 원활한 구동을 위하여 이렇게 인위적인 제한을 걸어두는 것이 필요한 경우가 충분히 발생할 수 있고, 특히 삼각함수의 역함수를 사용할 때 이와 같은 프로그래밍이 효과를 거둘 수 있음을 보여주는 좋은 예제인 것 같아 소개해봤습니다.

LIST