화요일, 8월 20, 2013

0.1 + 0.2 의 값은?

요즘 사무실에서 김과장이 산책 자바스크립트 프로그래밍 (프론트엔드 개발자를 위한)를 읽고 있습니다.


'니콜라스 자카스' 상당히 좋아하는 저자이지만, 역시 두꺼운 책(1,186페이지)은 읽기 어려운 것 같습니다. 손이 정말 잘 가지 않습니다. 그런데 오늘 퇴근 10분정도 남겨두고 잠깜 보고 갈까했는데, 아주 좋은 내용을 읽어서 이렇게 블로그에 정리해봅니다.

0.1 + 0.2 = ?

물음표의 값은 무엇일까요?, 당연히 우리는 0.3이라고 하겠지만 실제 JavaScript, C, Python, 등등 저희가 사용하는 대부분 모든 언어에서는 0.3이라고 나오지 않습니다.

크롬을 사용한다면 지금 F12를 눌러 Console탭에서 확인해보세요.
( sublime text를 사용한다면 ctrl+` )

JavaScript ( Chrome Console )
Python ( Sublime Text 3 )

자 이쯤되면 알고계신 분들이라면 고개를 끄덕이며 "당연한거 아냐"하시겠지만, 저처럼 정확한 이유를 모르시는 분들은 '머가 문제야!' 혹은 '왜!!'하면서 더운데 더 덥게한다면서 짜증을 내면서 컴퓨터를 끌지도 모르겠습니다.
( 한국전력 헌정 블로그였습니다. -_- )

노랑책(자바스크립트 프로그램밍)에서는 부동소수점 사칙연산은 정수 사칙연산보다 부정확하며, 오류가 아니라 IEEE-754에서 정의한 방식대로 계산했기 때문이라고 합니다. (계속 한국 전력 헌정 블로그입니다. -_-; )

컴퓨터에서 정보를 저장하기 위해서 비트형태 변환하여 저장한다는 사실은 거이 모두 알고 계실것 같습니다. 그리고 정수를 저장할 때는 이진법으로 오차없이 저장을 하게됩니다.

하지만 부동소수점(실수)를 저장할 때는 어떻게 저장할 까요?

IEEE-754에서 부동소수점을 저장하기 위해서는 아래의 그림 처럼 부호, 지수, 가수로 분리하여 저장합니다.


32비트에서는 부호 1비트, 지수 8비트, 가수 23비트로 저장한다고 합니다. 이제 0.1를 IEEE-754에서 정의한 방법으로 저장해봅시다. 그런데 부동소수점 이진법으로 어떻게 변경하는지 아세요?

곱하기2를 해서 1보다 크면 1, 작으면 0으로해서 변경합니다.
( 간단히 말해서 정수반대죠 )

0.1 x 2 = 0.2 이므로 1보다 작으니 0
0.2 x 2 = 0.4 이므로 1보다 작으니 0
0.4 x 2 = 0.8 이므로 1보다 작으니 0
0.8 x 2 = 1.6 드디어 커졌네요. 1, 그리고 0.6은 다시 반복
0.6 x 2 = 1.2 1보다 크므로 1
0.2 x 2 = 0.4 이므로 0 ( 앗 다시 0.4가 나왔네요. 아주 반갑네요. 사실 손 슬슬 아파 오거든요 )

따라서 0.1를 이진수로 변경하면 0.000110011... 이렇게 된다는 것을 알 수 있습니다.
암산으로 0.2도 계산해보면 0.00110011... 입니다.
( 0.2는 0.1에서 한칸씩 당겨져 있습니다. )

32비트에서 제일 큰 부분인 가수부분은 0.1, 0.2 둘다 '10011001100110011001101'이것으로 들어갑니다. 음 그렇쿤하고 넘어가셨는지 모르겠지만 실제 2진수 지수법으로 표기해 보면 아래와 같습니다.


2진수 지수법은 특성상 항상 맨앞이 1인 것을 알 수 있습니다. 그래서 조금이라도 더 많이 더 정확히 저장하기 위해 맨앞의 1은 저장하지 않습니다. 그러면 '10011001100110011001100'이 저장되어야 하는데 뒤부분이 '1100...'으로 무한 반복되기 때문에 반올림되어 '10011001100110011001101'이 저장됩니다.

즉 0.1, 0.2 모두 이 반올림 때문에 0.3 보다 조금 큰 실수가 나오게 됩니다. 자바스크립트로 확인을 해보면 아래와 같습니다.


실제 연산을 해보면 처음에 나왔던 수 보다 큰 것을 알수있습니다. 왜 더 큰지 -_-??
더 자세한 내용은 참고자료를 링크걸어둡니다.




참고자료
http://en.wikipedia.org/wiki/IEEE_floating_point
http://pub.mearie.org/ieee_754 : IEEE 754 옛날 영문 위키를 번역, 첫 링크에가면 추가된 내용이 많이 있습니다.
http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=177 : 소수점을 이진수로 변경하는 방법이 있음
http://itguru.tistory.com/199 : 모든 컴퓨터 과학자가 알아야 할 부동 소수점의 모든 것, 번역본이 있음.

댓글 1개:

Gaeun Kim :

좋은 글 감사합니다. 많은 도움 되었어요^^