IDL/Programming

NaN 값의 이해와 활용 [1]

이상우_idl 2016. 1. 8. 11:00
반응형

우리가 프로그래밍에서(꼭 IDL에만 국한된 문제는 아님) 각종 연산을 하다보면 NaN이라는 값을 종종 만나게 됩니다. NaN은 Not a Number의 약어로서, 직역을 하며면 "숫자가 아니다"라고 해석이 될텐데요. 좀 더 풀어서 얘기한다면, "숫자로서의 정상적인 값이 아니다" 정도의 의미로 생각하면 됩니다. 수학적으로 정상적인 연산이 불가함에도 불구하고 억지로 연산이 이루어질 경우 이러한 값이 산출됩니다. 예를 들면 다음과 같은 경우들입니다.


IDL> PRINT, SQRT(-5.7)

         -NaN

% Program caused arithmetic error: Floating illegal operand

IDL> PRINT, ALOG10(-6.2)

         -NaN

% Program caused arithmetic error: Floating illegal operand


이와 같이 (-)인 값에 대하여 제곱근 또는 로그(Log) 연산을 수행하는 경우 수학적으로는 정상적인 연산이 이루어지지 않습니다. 하지만 결과값 자체는 뭔가는 존재해야 하기 때문에 이러한 의미로 NaN이란 값이 주어지게 됩니다. 컴퓨터 프로그래밍에서나 존재하는 개념이라고 볼 수 있고, 그렇기 때문에 대다수의 프로그래밍 언어들이 이러한 NaN이라는 값을 어떤 식으로든 처리할 수 있도록 되어 있습니다. 물론 IDL도 마찬가지입니다. 그래서 이러한 NaN이란 값을 제대로 이해하고 처리하는 방법을 알아두는 것은 연산의 결과를 얻는데 있어서 매우 중요합니다. 이러한 관점에서 IDL에서 NaN값을 제대로 이해하고 어떻게 대처해야 하는지 그리고 어떤 식으로 이용할 수 있는가에 관한 얘기들을 몇 차례에 걸쳐서 소개해보고자 합니다.


먼저 다음과 같이 5개의 실수값들로 이루어진 배열이 있는 상태에서 제곱근 연산을 수행하고 그 결과를 얻어봅시다. 어디선가 NaN의 향기가 느껴집니다.


y = [3.7, 6.2, 8.3, -7.6, 5.5]

result = SQRT(y)

PRINT, result


출력된 결과값들은 다음과 같습니다. 역시나 NaN이 등장합니다. 배열안에 (-)인 값이 하나 있었기 때문입니다.


      1.92354      2.48998      2.88097         -NaN      2.34521


그런데 이 상태에서 result에 대하여 평균값을 구해보고자 합니다. 이 배열안에 있는 5개의 값들 중 하나는 NaN입니다. 이러한 상황에서 정상적인 평균값 연산이 가능할까요? 평균값 연산을 담당하는 MEAN이라는 내장함수를 이용해서 다음과 같은 연산을 수행하고 그 결과값을 봅시다.


PRINT, MEAN(result)


그러면 결과는 다음과 같이 NaN으로 얻어집니다.


         -NaN


어떻게 보면 당연한 결과이긴 합니다. 그런데, 대개의 경우 우리가 원하는 것은 배열안의 NaN값을 제외하고 나머지 정상적인 값들만을 대상으로 평균값을 얻는 것입니다. 그렇게 하려면 WHERE 함수같은 것을 사용해서 정상적인 값들만 골라내고, 그것을 대상으로 평균을 구하는 등의 과정이 필요할 수도 있습니다. 물론 이 방법도 가능하지만, 더 간단한 방법이 있습니다. IDL 도움말에서 MEAN 함수에 관한 내용을 찾아보면 다음과 같은 내용이 나옵니다.


Syntax

Result = MEAN( X   [, DIMENSION=value] [, /DOUBLE] [, /NAN] )


여기서 /NAN이라는 키워드가 보입니다. 이 키워드를 사용하면, 배열내에서 NaN인 값들을 제외한 나머지 정상적인 값들만을 대상으로 평균값 연산을 알아서 수행해줍니다. 따라서 다음과 같이 이 키워드를 사용하여 연산을 해주면 됩니다.


PRINT, MEAN(result, /NAN)


그러면 다음과 같이 정상적인 값들만을 대상으로 한 평균값을 얻을 수 있습니다.


      2.40992


이러한 /NAN 키워드는 MEAN 함수외에도 상당수의 연산 관련 내장함수들에 포함되어 있습니다. 따라서 사용하고자 하는 IDL의 내장함수가 /NAN 키워드를 지원하는가를 확인해두면 상당히 도움이 됩니다. 그리고 어떤 값이 NaN인가 여부를 명시적으로 확인할 수있도록 해주는 내장함수도 있습니다. 바로 FINITE라는 내장함수인데, 이 함수도 잘 알아두면 도움이 꽤 됩니다. 이 함수는 다음과 같이 사용하면 됩니다.


IDL> a = SQRT(-5.7)

% Program caused arithmetic error: Floating illegal operand

IDL> PRINT, FINITE(a)

   0

IDL> a = SQRT(6.2)

IDL> PRINT, FINITE(a)

   1


즉, 이와 같이 어떤 값에 대하여 FINITE 함수를 사용하면 0 또는 1이란 값을 돌려줍니다. 1이면 정상적인 숫자값이란 의미이고, 0이면 그렇지 않은 경우입니다. 그런데 방금 언급한 "그렇지 않은 경우"에는 NaN인 경우도 당연히 있지만, 또 다른 경우가 있습니다. 바로 무한대(Infinity)인 경우입니다. 다음과 같이 어떤 숫자를 0으로 나눌 경우 얻어지는 무한대 값도 연산에 있어서 무의미한 값이라는 점은 마찬가지입니다.


IDL> a = 4.7/0

% Program caused arithmetic error: Floating divide by 0

IDL> PRINT, FINITE(a)

   0


그래서 앞서 MEAN과 같은 내장함수가 /NAN 키워드와 함께 사용될 경우에는 대상배열내에 있던 NaN외에도 만약 무한대 값이 있을 경우 이러한 값도 역시 제외됩니다. 따라서 NaN과 무한대는 엄밀하게는 다르지만 연산에 있어서는 비슷하게 취급되는 경우가 많습니다.


* 다음 회 게시물에서 계속 이어집니다.

반응형