부동소수점에 대한 이해

부동 소수점 표현은 아주 큰 수와 아주 작은 수를 효율적?으로 표현하기 위해서 사용한다. 여기서 효율적이란 표현은 정확하다는 표현은 아니다. 효율적일 수록 오차가 발생하기 마련이다. 우선 부동소수점표현을 어떤 방식으로 하는지 이해하고, 오차가 발생할 수 밖에 없는 원리도 이해해보자.

부동 소수점

우선 우리가 10진수를 10으로 나누거나 곱하면 소수점의 위치를 변경할 수 있다. 이와 마찬가지로 2진수 또한 2로 나누거나 곱하면 소수점 위치가 한 칸씩 이동된다.(자세한 설명은 하지 않겠지만, 이 원리를 이용해 진수변환도 한다는 것을 알아 두자.) 부동 소수점은 이런 원리를 이용해서 소수점의 위치를 나타낸다. 예를 들어 1001.1011 이란 수가 있다면, 부동 소수점은 이 수를 1.0011011 * 2^3 으로 표현 한다. 여기서 3은 위에서 설명한 원리를 통해 소수점의 위치를 정하게 되고 앞에 1.0011011은 1001.1011을 정규화한 것이다.

정규화 방법

정규화 방법은 정수부에 1만 남기도록 소수점을 이동하고 소수점에 관한 정보는 2^x으로 표현하는 것이다. 이런 표현은 고정 소수점 보다 효율적으로(적은 비트로) 큰 수를 표현할 수 있다.

부동 소수점 구조 알아보기

위 그림은 c/c++에서 float형의 표현 방식이다.

부호부 : 표현할 값이 0인 경우 양수, 1인 경우 음수

지수부:(2의 8승) -1가지 표현을 할 수 있다. 다시 말하면 2진수 체계에서 주어진 가수의 (2의 8승) -1가지 자리수 표현이 가능하다.

가수부: 가수부는 수의 모양을 알려주는데, 위에 예시의 수의 가수부는 00110110000000000000000(23자리)이 된다. 23bit(자리수)가 갖는 한계와 특징에 대해서는 따로 설명하겠다.

 

지수부

부동 소수점의 지수부는 컴퓨터가 수를 표현하는 일반적인 방식과 다르다. 바이어스(bias)표현 법인 이 방법을 알면 부동 소수점에 대해서 80%는 이해했다고 보면 된다.

예를 들어 char형 자료형으로 수를 표현하는 방법은 다음과 같다.

0000 0000 : 0

...

0111 1111 : 127

1000 0000 : -128

1000 0001 : -127

...

1111 1111 : -1

-128~127 까지 수를 표현

이렇게 음수를 표현하는 방법을 2의 보수법이라고 한다.

아무튼 char 뿐 아니라 int형도 이런 식으로 표현된다.

 

바이어스 표현법

지수부가 8bit인 부동 소수점을 표현할 때, 바이어스 표현법은 다음과 같다.

0000 0000 : -127

0000 0001 : -126

....

0111 1111 : 0

....

1111 1111 : 128

이런 식으로 표현하는 이유는 일반적인 정수를 나타낼 때와 지수를 나타낼 때, 0과 음수의 의미가 다르기 때문이다. 여러 특징이 있겠지만, 우선 밑이 양수인 경우 지수가 음수여도 값은 양수가 되기 때문이고, 지수가 음의 무한대로 뻗어나가더라도 밑이 무한히 0에 가까운 수가 된다.(0보다 큼)

따라서, 지수부가 8bit인 경우 가장 작게 표현할 수 있는 -127의 경우를 0000 0000으로 표현한다.

 

바이어스 상수

여기서는 IEEE754표준인 127바이어스법(8bit)을 기준으로 한다.

바이어스 상수 : 2^(n-1)-1

n:비트부 자리수(여기서는 8bit)

 

64바이어스법은 바이어스 상수가 100 0000이 되는데, 여기서는 127바이어스 법만 다룬다.

 

2의 보수법 + 바이어스 상수 = 바이어스 표현법

 

예를 들어 2의 보수법으로 127을 표현하면 0111 1111 이고 이를 바이어스 표현법으로 바꾸려면(float형) 127((2^8)-1)을 더하면 된다.

0111 1111 + 0111 1111 = 1111 1110 (127 바이어스 법으로 표현한 127)

 

예) -0.4를 16부동 소수점으로 바꾸어라. ( 지수부 5bit, 가수부 10비트)

0.4 = 0.0110011001100110...(2진수) = 1.1001100110...*2^-2

따라서 지수부는 -2가 된다. -2를 2진수로 나타내면(2의보수법) 1 1110이 된다.

지수부 비트가 5bit므로 바이어스 상수는 2^5-1 = 15 = 0 1111

지수부를 바이어스 표현 법으로 나타내기 위해 위 두값을 더한다.

1 1110 + 0 1111 = 0 1101

따라서,

1 0 1101 1001100110

 

예) 19.25를 127 바이어스법으로 바꾸면

19.25

= 10011.01(2진수)

= 1.001101 * 2^4

4 = 100(2진수)

여기서 비트부를 바이어스법으로 바꾸면

100 + 0111 1111 = 1000 0011이 된다.

따라서 0100 0001 1001 1010 0000 0000 0000 0000

로 표현할 수 있다.

 

0을 표현하는 방법

바이어스 표현 방법으로 지수의 표현은 -127 ~ 128까지 가능하다. 그러면 0의 표현은 어떻게 할까? 상식적으로 생각하면 0은 표현할 수 있는 가장 작은 양수 보다 작거나 같아야 한다. 부동 소수점 표현에서 표현할 수 있는 가장 작은 수는 다음과 같다.

따라서 모두 0인 경우를 0으로 하기로 한다.

 

2^-127보다 작은 수 표현

그런데 32bit float가 표현할 수 있는 가장 작은 수는 2^149이다. 위에서 모든 비트가 0으로 채워진 경우(지수부가 -127승인 경우)는 0을 표현한다고 했다. 그러면 어떻게 2^-127승 보다 더 작은 수는 어떻게 표현하는 것일까?

규칙

지수부가 모두 0인 경우는 특별한 경우로 나누어 생각하는 것이 좋다.

모든 비트가 0인 경우는 0을 나타낸다.(위에서 살펴봄)

지수부의 비트가 0이지만 가수부의 비트는 0이 아닌 경우, 유효수에서 정수값을 1이 아닌 0으로 한다. 그리고 지수값을 -126으로 약속 한다.

예를 들어,

0.00000000010000000001000 * 2^-126

0.10000000000000000000000 * 2^-126 = 2^-127

0.00000000000000000000001 * 2^-126 = 2^-149

따라서 32bit float형의 표현할 수 있는 가장 작은 수는 2^-149승이 된다.

참고로 2^-126은 다음과 같다.

1. 00000000000000000000000 * 2^-126 = 2^-126

 

지수부 비트가 모두 1로 채워진 경우

우선 이 경우 지수부는 128을 나타내는데 가수부의 형태에 따라서 두 가지 상태를 나타낸다.

가수부 비트가 모두 1인 경우 inf를 나타냄(무한)

가수부 비트가 모두 1이 아닌 경우 nan을 나타냄(미정값)

 

최대값

0x7f7fffff float자료형이 표현할 있는 가장 수가 된다. 약 2^128승정도가 되는데

이런 식으로 표현된다.

 

부동 소수점의 오차

부동 소수점은 적은 비트로 큰 수를 표현할 수 있지만, 이런 효율성은 정확성을 떨어뜨릴 수 밖에 없다. float의 가수부의 크기는 23bit인데, 23은 실제로 값자리수(길이)를 나타낸다. 부동 소수점의 표현 방식상 정수값 자리수가 23을 넘어가게 되면 소수점 이동이 23(가수의 길이)이 넘어가므로 가수부의 길이를 초과하여 소수점 이하를 표현할 길이 없어진다. 길이를 넘어가게 되면 가수의 마지막 자리 값은 넘어간 수만큼의 0이 생긴다.

지수값이 24인 경우 0이 하나 생겼다. 2진수의 LSD(least significant Digit)가 무조건 0이기 때문에 홀수를 표현할 수 없다.

지수값이 25가 되면 0이 두개 생긴다. 따라서 4의 배수만 표현된다. 이런 식으로 오차가 점점 늘어나는데, 사실 이런 오차는 지수값이 23이넘어가면 값의 크기에 비해서 아주 작은 값이 되므로 그렇게 큰 차이는 아니지만, 정밀도가 떨어질 수밖에 없다. 따라서 double 타입의 자료형을 사용하면 이런 오차를 좀 더 줄일 수 있다.

이 댓글을 비밀 댓글로
  1. 굉장한 도움이 되었습니다.

    북마크 저장해두고 자주 들리겠습니다.

    감사합니다.
    • 요새 바뻐서 자주 글을 못쓰는데도 이렇게 글을 남겨주셔서 감사합니다.
    • 1ㅁ2ㅁㅁ
    • 2017.06.12 15:59
    어떤 책보다 이해가 잘되는것 같습니다. 감사합니다
    • 감사요
    • 2017.10.09 20:01
    대학강의 참고용으로 잘 보았습니다.
    • 2018.09.16 17:06
    비밀댓글입니다
    • assembly
    • 2018.12.28 16:15
    19.25를 127bias로 변환시키는 예제 마지막 결과에서
    지수부의 마지막 1이 주황색으로 표현되어 있네요
  2. 2^-149아닌가요 -를 빼신듯
    • chan
    • 2021.05.03 01:57
    지수부에서 -127~128또는 -128~127 인데 지수부의 가지수가 (2의 8승)-1가지가 맞나요?
    • 라인
    • 2021.07.10 17:46
    안녕하세요! 부동소수점 이해하는데 많은 도움 되었습니다. 감사해요!

    그런데 혹시 마지막 오차 설명하시는 부분에서 정수값의 자리수가 23이 넘어가면 안된다고 하셨는데 24자리도 안되는 건가요? 24자리 정수일 경우 소수점이 없는 상태에서 23자리 이동하니 맨 앞 1은 고정으로 표현 안하고 소수점 뒤로간 23개를 가수부 23자리에 넣으면 될 것 같아서요.