IDL/Data Type & Format

실수의 소수점 이하 자릿수 변경 방법

이상우_IDL 2018. 7. 30. 16:29
728x90

오늘은 실수의 소수점 이하 자릿수를 변경하는 방법에 관하여 알아보겠습니다. 참고로 이 내용에서는 제가 예전에 다룬 적이 있었던 형변환 함수들이 사용됩니다. 따라서 관련 게시물의 내용도 함께 참조하시면 좋을 것 같습니다. 그러면 예를 들어 다음과 같이 a라는 변수에 1.2745라는 값이 있다고 합시다.


IDL> a = 1.2745


그런데 이 값이 소수점 이하 두번째 자릿수까지만 의미가 있어서 그 밑으로는 다 쳐내고 1.27이란 값으로 다뤄야 할 경우가 있을 수 있습니다. 그럴 때에는 다음과 같이 FIX 함수를 적절히 응용하면 됩니다.


IDL> PRINT, FIX(a*100)/100.

      1.27000


여기서는 먼저 a에 100을 곱해서 127.45를 만든 다음 FIX 함수를 적용하여 127이라는 정수로 만들어 이를 100.으로 나눠서 1.27로 만드는 3단계의 과정을 거친 것입니다. 특히 막판에 100으로 나누는 것이 아니라 100.0으로 나눠서 실수 연산이 되도록 해야 한다는 점만 신경쓰면 됩니다. 만약 a가 1.2769라면 어떻게 될까요?


IDL> a = 1.2769

IDL> PRINT, FIX(a*100)/100.

      1.27000


이렇게 해도 어차피 결과는 1.27입니다. FIX 함수는 반올림을 하지 않기 때문입니다. 반올림이 적용되도록 하려면 FIX 대신 ROUND 함수를 사용하면 됩니다. 그러면 다음과 같이 차별적으로 결과를 산출합니다.


IDL> a = 1.2769

IDL> PRINT, ROUND(a*100)/100.

      1.28000

IDL> a = 1.2745

IDL> PRINT, ROUND(a*100)/100.

      1.27000


따라서 실수의 소수점 이하 자릿수를 제한하여 작업해야 할 경우에는 기본적으로 위와 같은 방법을 사용하면 됩니다. 그런데 반올림을 반영하는 방식을 따른다고 한다면 좀 다른 방법도 있습니다. 이 방법에서는 다음과 같이 STRING 함수를 사용하여 실수값을 문자형으로 변환하는 과정을 거치게 됩니다.


IDL> a = 1.2745

IDL> a_str = STRING(a, FORMAT='(F0.2)')

IDL> PRINT, a_str

1.27


여기서는 a가 1.2745일 때 이 값에 대하여 STRING 함수를 적용하여 문자형으로 변환한 값을 a_str이란 변수에 일단 저장하였습니다. 여기서 주목할 부분은 STRING 함수에서 FORMAT 키워드에 명시된 서식입니다. 서식에서 F는 실수형을 뜻합니다(참고로 실수형 서식에 관해서는 제가 예전에 올렸던 관련 게시물도 있으므로 필요하시면 이 내용을 보시면 됩니다). 사실 이러한 서식을 사용할 때에는 예를 들어 '(F6.2)'와 같은 방식으로 필드수와 자릿수를 명시하면서, 필드수를 자릿수보다 더 크게 잡아주는 것이 일반적입니다. 따라서 여기서는 '(F4.2)'라고 적어도 됩니다. 하지만 위의 예제코드에서는 필드수를 0으로 명시했는데, 이것은 필드수가 정확히 얼마가 될지 모르는 상황이라 하더라도 마치 와일드카드처럼 어떤 크기가 되든 거기에 맞추라는 얘기입니다. 예를 들어 a가 1.2745가 아니라 58.2745가 될 경우라면 서식은 '(F4.2)' 대신 '(F5.2)'가 되어야 할 것입니다. 하지만 서식을 위와 같이 애초에 '(F0.2)'로 명시하면 a의 값의 크기에 따라 필드수가 변하더라도 유저는 그때마다 필드수를 수정하지 않아도 됩니다. 어쨌든 위와 같이 일단 문자형으로 서식 기반으로 변환을했다가 다음과 같이 다시 실수형으로 변환하면 됩니다.


IDL> a_new = FLOAT(a_str)

IDL> PRINT, a_new

      1.27000


여기서는 실수형으로 변환한 값은 a_new라는 변수에 따로 저장하였습니다. 중간 과정을 약간 생략해서 다음과 같이 해줘도 됩니다.


IDL> a_new = FLOAT(STRING(a, FORMAT='(F0.2)'))

IDL> PRINT, a_new

      1.27000


이 방식은 a의 값이 바뀌더라도 잘 작동합니다. 다음과 같이 a가 1.2769가 되면 반올림이 적용됩니다.


IDL> a = 1.2769

IDL> a_new = FLOAT(STRING(a, FORMAT='(F0.2)'))

IDL> PRINT, a_new

      1.28000


그리고 a의 값이 더 크더라도 동일한 코드로 처리가 됩니다. 서식에서 필드수를 바꿔주지 않아도 됩니다.


IDL> a = 58.2745

IDL> a_new = FLOAT(STRING(a, FORMAT='(F0.2)'))

IDL> PRINT, a_new

      58.2700


그런데 만약 a가 다음과 같이 굉장히 큰 값일 경우는 어떻게 될까요? 실제로 해보면 다음과 같이 좀 엉뚱한 결과가 나옵니다.


IDL> a = 735918.2745

IDL> a_new = FLOAT(STRING(a, FORMAT='(F0.2)'))

IDL> PRINT, a_new

      735918.


사실 이러한 경우에 대해서는 주의를 기울일 필요가 있습니다. 이것은 일반 실수형(Float)의 유효숫자 갯수 한계 때문입니다. 일반 실수형의 유효숫자는 소수점의 위치에 관계없이 6~7개 정도라고 보면 됩니다. 따라서 위와 같이 a가 백만에 근접하는 값일 경우에는 소수점 이하 숫자들은 유효숫자의 범주에서 벗어가게 되는 바람에 이렇게 이상한 결과가 나온 것입니다. 더 많은 유효숫자가 필요하다면 자료형을 일반실수형이 아닌 2배 정밀도 실수형(Double Precision)으로 바꿔줘야 합니다. 즉 다음과 같이 모든 과정이 2배 정밀도 실수형 기반에서 진행되어야 합니다.


IDL> a = 735918.2745D

IDL> a_new = DOUBLE(STRING(a, FORMAT='(F0.2)'))

IDL> PRINT, a_new

       735918.27


여기서 주의해야 할 부분이 두가지가 있습니다. 먼저 a의 값을 명시할 때 알파벳 D를 붙여서 숫자값의 자료형이 2배 정밀도 실수형임을 명확히 해줘야 한다는 것이고, 문자값을 숫자로 변환할 때 FLOAT 대신 DOUBLE이라는 형변환 함수를 사용해야 한다는 것입니다. 이러한 점들만 주의하면 됩니다. 실제로 2배 정밀도 실수형은 유효숫자 갯수 한계가 약 15~16개 정도이기 때문에 저 정도 상황에서는 충분히제 역할을 합니다.


사실 실수형 값의 유효숫자 문제는 비단 IDL에서만의 문제라기보다는 컴퓨터 프로그래밍 세계에서 공통적으로 엄연히 존재하는 문제이며, 어느 정도 아니면 굉장히 세심한 주의가 필요한 경우들도 있습니다. 이 문제에 관해서는 나중에 기회가 되면 한번 다뤄보기로 하겠습니다.

LIST