IDL/배열 생성 및 처리

배열의 자료형과 값의 대입에 관한 유의사항

이상우_idl 2020. 9. 14. 16:33
728x90
반응형

IDL에서 단일값 변수의 경우는 자료형이 동적으로 정의됩니다. 즉 대입되는 값에 따라서 자료형이 정의됩니다. 예를 들어 a라는 변수를 다음과 같이 정의하면 변수 a는 정수형 변수로 정의됩니다.

 

IDL> a = 7

IDL> HELP, a

A               INT       =        7

 

이랬다가 바로 a에 실수형 값을 대입하면 바로 실수형 변수로 바뀝니다.

 

IDL> a = 5.6

IDL> HELP, a

A               FLOAT     =       5.60000

 

이와 같이 변수를 처음 사용할 때 대입되는 값에 따라서 변수의 자료형이 동적으로 유연하게 정의됩니다. 그런데 배열의 경우는 어떨까요? 배열의 경우는 조금 다릅니다. 설명을 위하여 먼저 다음과 같이 정수형 값들로 구성된 배열 a를 정의합니다.

 

IDL> a = [6, 4, 7]

IDL> HELP, a

A               INT       = Array[3]

 

이렇게 정의된 배열 a는 당연히 정수형 배열이 됩니다. 그러면 여기서 다음과 같이 배열 a의 첫번째 원소값에 대하여 실수형 값을 대입해봅시다.

 

IDL> a[0] = 8.6

 

그리고 바로 이어서 배열 a에 대한 정보를 확인해보면 결과는 다음과 같습니다.

 

IDL> HELP, a

A               INT       = Array[3]

IDL> PRINT, a

       8       4       7

 

이와 같이 배열 a는 여전히 정수형 배열입니다. 사실 이 부분에 대해서는 배열 자체는 정수형이었다 하더라도 실수값을 대입하면 배열이 실수형으로 알아서 바뀌는 것은 아닐까 하는 생각을 할 수도 있는데요. 배열의 자료형은 값의 대입에 의하여 동적으로 바뀌지않는다는 것을 유의해야 합니다. 단일값 변수의 경우와는 엄연히 다릅니다. 그리고 a[0]에 대입했던 8.6이란 실수형 값은 실제로는 8이라는 정수형 값으로 들어가 있습니다. 배열의 자료형이 정수형 그대로이기 때문에 대입되는 값은 정수형으로 변환되어 들어간 셈입니다. 그러면 그 반대의 경우도 한번 볼까요? 이번에는 다음과 같이 실수형 값들로 구성된 배열 a를 먼저 정의합니다.

 

IDL> a = [7.3, 4.2, 5.6]

IDL> HELP, a

A               FLOAT     = Array[3]

 

이렇게 정의된 배열은 실수형 배열이 됩니다. 여기서 다음과 같이 배열 a의 첫번째 원소값에 대하여 정수형 값을 대입해봅시다.

 

IDL> a[0] = 8

 

그리고 바로 이어서 배열 a에 관한 정보를 확인해보면 다음과 같습니다.

 

IDL> HELP, a

A               FLOAT     = Array[3]

IDL> PRINT, a

      8.00000      4.20000      5.60000

 

이와 같이 대입된 정수형 값 8은 실수형 배열 내에서 실수형으로 변환되어 들어가게 됩니다. 이러한 결과는 앞서 정수형 배열에 실수형 값을 대입한 경우와 근본적인 맥락이 같습니다. 즉 배열 내의 일부 값(들)을 대입에 의하여 대체하고자 할 경우에는, 대입되는 값들은 배열 자체의 자료형에 맞게 변환되어 들어가게 된다는 것입니다. 물론 대입될 값(들)과 배열의 자료형이 일치할 경우가 가장 이상적이겠지만, 실제로 작업을 하다보면 그렇지 않을 경우도 종종 있을 것입니다. 따라서 배열과 대입값의 자료형이 일치하지 않을 경우에는 예기치못한 문제가 발생할 가능성이 있음을 유의해야 합니다. 바이트(Byte)형 배열의 경우에도 특별한 주의가 필요합니다. 예를 들어 다음과 같이 바이트형 값들로 구성된 배열 a를 먼저 정의해봅시다.

 

IDL> a = [33B, 148B, 220B]

IDL> HELP, a

A               BYTE      = Array[3]

IDL> PRINT, a

  33 148 220

 

그런데 여기서 다음과 같이 a[0]에 대하여 정수형 값 430을 대입한 후 그 결과를 확인해봅시다.

 

IDL> a[0] = 430

IDL> HELP, a

A               BYTE      = Array[3]

IDL> PRINT, a

 174 148 220

 

이 결과를 보면 a[0]에 실제로 들어간 값은 174입니다. 정확히 말하면 바이트형으로 변환된 값이기 때문에 174B라고 해야 맞습니다. 어쨌든 애초에 대입한 값은 430인데 어떻게 174라는 값으로 들어갔을까요? 그것은 바이트형 값 자체가 0~255의 범위만 가능하기 때문입니다. 따라서 255를 넘는 값이 대입되면 다시 0으로 되돌아간 값으로 인식됩니다. 다음과 같은 방식으로 테스트해보면 이해가 쉽습니다.

 

IDL> a[0] = 254

IDL> PRINT, a

 254 148 220

IDL> a[0] = 255

IDL> PRINT, a

 255 148 220

IDL> a[0] = 256

IDL> PRINT, a

   0 148 220

IDL> a[0] = 257

IDL> PRINT, a

   1 148 220

IDL> a[0] = 258

IDL> PRINT, a

   2 148 220

 

즉 이와 같은 원리로 따져보면 430-256=174가 되므로 174로 인식된 것입니다. 우리가 자주 다루게 되는 데이터들 중에 특히 이미지 데이터들이 주로 이와 같이 바이트형 값들로 구성되는 경우가 많습니다. 그런 경우에는 이와 같은 특성을 반드시 유의해야 합니다. 따라서 배열에 대하여 어떤 값을 대입하고자 할 경우에는, 대입할 값과 배열의 자료형이 서로 일치하도록 사전에 조치를 해두는 것이 좋습니다. 위의 경우에 대해서는 예를 들면 다음과 같이 처리하는 방법이 있습니다.

 

IDL> a_new = FIX(a)

IDL> HELP, a_new

A_NEW           INT       = Array[3]

IDL> a_new[0] = 430

IDL> PRINT, a_new

     430     148     220

 

즉 원본 배열 a는 바이트형이었는데 이 배열을 정수형으로 변환한 a_new라는 배열을 새로 정의하여 이 배열에 대하여 대입을 수행하는 것입니다. 여기서는 원본 배열 a를 살려두기 위하여 이러한 방식으로 처리를 한 것인데, 그냥 a = FIX(a)와 같은 식으로 배열 a 자체를 아예 형변환을 시켜버린 후 처리하는 방법도 있을 것입니다.

 

가끔 저에게 오는 IDL 관련 문의들 중에, 배열 내에 NaN값을 대입하는 경우에 대한 문의가 있습니다. 이를 위하여 !values.f_nan이라는 값을 사용하게 되는데요. 여기서 반드시 유의할 것은 !values.f_nan 값은 실수형이라는 것입니다. 따라서 이를 대입할 대상 배열은 반드시 실수형 배열이어야 합니다. 예를 들어서 다음과 같이 정수형 배열의 일부분에 대하여 NaN 값을 대입해봅시다.

 

IDL> a = [45, 82, 69]

IDL> HELP, a

A               INT       = Array[3]

IDL> a[0] = !values.f_nan

% Program caused arithmetic error: Floating illegal operand

 

그러면 이와 같이 문제가 발생합니다. 더군다나 이 상태에서 배열 a의 값들을 출력해보면 다음과 같습니다.

 

IDL> PRINT, a

       0      82      69

 

즉 이와 같이 NaN이 아닌 0이라는 값으로 인지된 상태가 됩니다. 배열 a가 바이트형일 경우에도 동일한 문제가 발생합니다. 여기서 발생한 arithmetic error는 사실 에러(Error)라기 보다는 경고(Warning)라고 봐야 합니다. 그리고 프로그램의 실행 과정에서 에러는 실행을 중단시키지만 경고는 실행을 중단시키지는 않는다는 것을 반드시 유의해야 합니다. 따라서 어떤 프로그램 내에서 이러한 내용이 존재할 경우에는 중간에 경고 메시지는 출력되겠지만 실행 자체는 그대로 이어지기 때문에, 그 프로그램의 최종 실행 결과를 그대로 맹신했다가는 큰 문제가 발생할 수도 있습니다. 따라서 이러한 부분에 대해서는 프로그래머 자신이 각별히 신경을 써야만 합니다. 어쨌든 NaN값의 대입을 위해서는 원본 배열 자체가 실수형이어야 합니다. 따라서 다음과 같은 방식의 처리가 하나의 해결책이 될 수 있습니다.

 

IDL> a = [45, 82, 69]

IDL> HELP, a

A               INT       = Array[3]

IDL> a_new = FLOAT(a)

IDL> HELP, a_new

A_NEW           FLOAT     = Array[3]

IDL> PRINT, a_new

      45.0000      82.0000      69.0000

 

즉 이와 같이 원본 정수형 배열 a를 실수형으로 변환한 a_new라는 배열을 새로 정의하여 다음과 같이 이 배열에 대하여 대입을 수행하는 것입니다.

 

IDL> a_new[0] = !values.f_nan

IDL> PRINT, a_new

          NaN      82.0000      69.0000

 

그러면 이와 같이 원래 의도했던 방식대로 처리가 될 것입니다. 따라서 배열 내의 값을 다른 값으로 대체하고자 할 경우에는 배열의 자료형과 대체할 값의 자료형이 일치하도록 해야 제대로 된 결과를 얻을 수 있다는 점을 항상 주의하시기 바랍니다.

반응형