커뮤니티

분류1

자유게시판

제목

부동 소수점(Floating Point)란 무엇인가?

부동 소수점(Floating Point)란 무엇인가?

in #kr • 2 years ago

iron_modolee.png
안녕하세요. 개발자 모도리입니다.

이번에는 잠시 다른 주제를 다뤄 보겠습니다. (EOS Dapp 개발 공부를 못하고 있습니다.) 부동 소수점이란 무엇인가 알아보도록 하겠습니다. 이 주제 선택한 이유는 @creamer7님께서 작성하셨던 [EOS 속보] 댄으로 부터 온 메세지 + 댄이 직접 대답하는 Q & A 의 댓글에서 시작되었습니다.^^;

전반적인 내용을 다 다루려면 분량이 너무 길어 질 것 같아서, 음수 부분은 생략하고 양수에 대한 부분만 작성하겠습니다.

정수를 표현하는 방식

일반적으로 사람이 표현하는 숫자 123을 표현하는 방식에는 여러가지가 있습니다. 우리가 일상적으로 사용하는 숫자 표현방식은 10진수입니다. 123을 여러가지 표현방식으로 나타내면 아래와 같습니다. 자세한 진법 변환 방법은 아래 참고 자료에 첨부하겠습니다.

  • 16진수 : 7B
  • 10진수 : 123
  • 8진수 : 173
  • 2진수 : 1111011

컴퓨터가 실수를 표현하는 방식

2진수 표현

컴퓨터는 숫자를 표현할 때 기본적으로 2진수를 사용합니다.
아래 표를 참고해서 숫자를 나타내 보면

  • 13 = 8 + 4 + 1 이므로 해당 자리 숫자를 1로 표현하고 나머지는 0으로 표현합니다. 그러면 1101이 됩니다.

  • 0.75 = 0.5 + 0.25 이므로 0.11 로 표현할 수 있습니다.

binary.png

이렇게 쉽게 끝나면 얼마나 좋을까요! ㅠㅠ

263.3 같은 실수를 2진수로 표현해 보면
(상세 방법은 유튜브 영상에 자세히 나와 있습니다.)

  • 263 => 100000111
  • 0.3 => 0.01001100110011......(0011)의 무한 반복입니다.
    이렇게 2진수로 표현하지 못하는 소수가 발생합니다. 어쩔 수 없이 컴퓨터에는 표현할 수 있는 가장 근사치의 값이 저장됩니다.

이 근사 값을 저장하는 방법에는 두 가지가 있습니다.

고정 소수점

  • 정수를 표현하는 비트 수와 소수를 표현하는 비트 수를 미리 정해 놓고 해당 비트 만큼만 사용해서 숫자를 표현하는 방식
  • 예) 실수 표현에 4byte(32bit)를 사용하고 그 중 부호(아래에서 괄호로 표시) 1bit, 정수 16bit, 소수 15bit를 사용하도록 약속해 놓은 시스템에 있다고 가정합니다. 이렇게 약속 된 시스템에서 263.3을 표현하면 (0)0000000100000111.010011001100110 이렇게 표현됩니다.
  • 정수를 표현하는 bit를 늘리면 큰 숫자를 표현할 수 있지만 정밀한 숫자를 표현하긴 힘듭니다. 그래서 소수를 표현하는 bit를 늘릴 경우 정밀한 숫자를 표현할 수 있지만 큰 숫자를 표현하지 못합니다.

이런 문제를 해결하기 위해서 소수점을 고정하지 않고 둥둥 떠 다닐 수 있게 하는 부동 소수점(floating point)을 사용하고 있습니다.

부동 소수점

부동 소수점을 표현하는 방식도 정하는 방식에 따라 다를 수 있지만 일반적으로 사용하고 있는 방식은 IEEE에서 표준으로 제안한 방식입니다.
IEEE754.png

우선 고정 소수점으로 나타낸 263.3을 2진수 부동 소수점 방식으로 변환해 보겠습니다. 100000111.010011001100110... 으로 표현되던 것을 맨 앞에 있는 1 바로 뒤로 소수점을 옮겨서 표현하도록 변환합니다. 그러면 1.00000111010011001100110... * 2^8(2의 8승) 으로 표현 됩니다.

  • 2^8의 8을 지수라고 하고 하늘색 부분에 기록합니다. (IEEE 754 표현 방식에서는 127 + 지수를 기록합니다.)
  • 소수점 이후 숫자열 전체를 가수라고 하고 연두색 부분에 기록합니다.

이 방식에 따라서 263.3을 기록하면

  • 부호 비트(1 bit) : 0 (양수)
  • 지수 비트(8 bit) : 10000111 (127 + 8 = 135)
  • 가수 비트(23 bit) : 00000111010011001100110
    이렇게 표현할 수 있습니다.

하지만! 여기서도 0.010011001100110은 정확히 0.3을 나타낼 수는 없습니다. 10진수로 나타내 보면 0.29998779296875을 나타냅니다.

부동 소수점 오류 예

0.1을 100번 더하면 10이 나와야 되는데...
0.1을 정확히 표현할 수 없기 때문에 발생하는 오류입니다.

JAVA

example_java.png

Python

example_python.png

C

example_c.png

만약 이렇게 오류가 발생할 수 밖에 없는 부동소수점 연산을 블록체인 상에서 사용한다면 어떤 일이 벌어질까요? Token Decimal이 18자리인 EOS의 경우 0.3 EOS를 전송했는데, 갑자기 중간에 0.0000122070312499889 EOS가 훅~ 증발해 버립니다. ㅠㅠ

그래서 이런 일이 일어난 것을 방지하기 위해서 블록체인 구현 시 floating point 연산 지원을 하지 않습니다. 그럼 어떻게 소수점 단위로 코인(토큰)을 주고 받을 수 있을까요?

블록체인 구현 시 부동 소수점 처리

비트코인

  • 분할 가능 범위 : 소수점 아래 8자리
  • 0.00000001 BTC = 1 Satoshi
  • 1 BTC = 100000000 Satoshi

이더리움

  • 분할 가능 범위 : 소수점 아래 18자리
  • 0.000000000000000001 Ether = 1 Wei
  • 1 Ether = 100000000000000000 Wei

참고로 Gas비 계산에 사용되는 Gwei는

  • 1 Gwei = 1000000000 Wei
    입니다.

이오스

지난 번 포스팅
[EOS] Smart Contract 개발 준비 3 - 샘플 스마트 컨트랙트 실행
에서 샘플컨트랙트 실행 과정에서 1000.0000 CUR를 초기 발행했는데, balance를 확인해 보면 10000000 이라고 찍혀 있는 것을 확인하셨을 겁니다.

혹시 감이 오시나요??

사실 실제로 내부적으로 거래가 일어날 때에는 해당 코인의 가장 작은 단위를 이용해서 실수 연산이 아닌 단순 정수 연산을 수행하고 있었습니다. 사용자가 0.00000001 BTC를 전송할 경우 transaction에 0.00000001 BTC가 실려 가는 것이 아니라 그냥 1 Satoshi이 실려 가는 겁니다. 그래서 부동 소수점으로 인한 오류를 신경쓰지 않아도 되는 것이고요.
물론 서버간의 통신에서는 문제가 없겠지만, 다른 3rd party 클라이언트에서 이런 문제를 인식하지 못하고 그냥 구현하게 될 경우 발생하는 문제를 A note on numbers in Ethereum and Javascript에서 다루고 있습니다.

@creamer7님과@sirin418님 덕분에 몰랐던 사실을 알게되었네요. 감사합니다.^^

다음에는 다시 EOS Dapp 개발 포스팅으로 돌아오겠습니다~!!

참고 자료

0

추천하기

0

반대하기

첨부파일 다운로드

등록자naver21

등록일2020-06-11

조회수4,464

  • 페이스북 공유
  • 트위터 공유
  • 인쇄하기
 
거친 말, 욕설, 모욕 등은 삭제 처리될 수 있습니다.
댓글로 인해 상처받는 분이 없도록 서로 예의를 지켜 주시기 바랍니다. ~ ♬
스팸방지코드 :