본문 바로가기
Language/Java

[Java] 실수형의 정밀도, 고정소수점과 부동소수점

by 계범 2022. 2. 27.

실수형의 정밀도

float은 4byte로 이루어져있고,

4byte의 정수로는 '약 ±2x10^9'의 값 밖에 표현할 수 없었는데,

어떻게 3.4 x 10^38 과 같은 큰 값을 표현할 수 있는가?

 

그 이유는 실수는 값을 저장하는 방식이 다르다.

 

정수형 int : 1 + 31 = 32(4byte)

S(1) 31 bit

실수형 float : 1 + 8 + 23 = 32(4byte)

S(1) E(8) M(23)

 

정수형은 부호와 값으로 이루어져있지만,

실수형은 '부호(S), 지수(E), 가수(M)' 세 부분으로 이루어져 있다.

즉, '2의 제곱을 곱한 형태로 저장하기 때문에 이렇게 큰 범위의 값을 저장하는 것이 가능하다.

 

그러나 정수형과 달리 실수형은 오차가 발생할 수 있다는 단점이 있다.

그래서 실수형에는 표현할 수 있는 값의 범위뿐만 아니라 '정밀도'가 중요한 요소이다.

 

float의 정밀도는 7자리인데,

'7자리의 10진수를 오차없이 저장할 수 있다'란 뜻이다.

 

1234.567          = 1.234567 x 10^3

0.00001234567  = 1.234567 x 10^-5

1234567000      = 1.234567 x 10^9

 

만일 7자리 이상의 정밀도가 필요하다면, double을 써야한다.

double은 float의 2배인, 15자리의 정밀도를 가지고 있다.

 

연산속도의 향상이나 메모리를 절약하려면 float을 선택,

더 큰값의 범위라던가 더 높은 정밀도를 필요로 한다면 double을 선택

 

실수형 값을 출력할때는 printf 메서드의 지시자 '%f'를 사용한다.

'%f'의 기본값은 소수점이하 6자리까지 출력하므로, 7번째 자리에서 반올림된다.

 

그 이상을 원할 경우 '%24.20f' 형태로 쓰면 된다.

(전체 24자리 중에서 20자리는 소수점 이하의 수를 출력하라는 뜻)

 

실수의 저장형식

실수형을 저장하는 방식은 두가지가 있는데, 고정소수점과 부동소수점이 있다.(대부분 부동소수점을 사용)

그리고 정수형과 달리, '2의 보수법'을 사용하지 않기 때문에 양의 실수를 음의 실수로 바꾸려면 그저 부호비트만 0에서 1로 변경하면 된다.

고정 소수점(Fixed point)

(32비트기준)

고정 소수점은 첫번째 칸은 부호비트, 15칸은 정수부, 16칸은 소수부로 부른다.

 

부호비트는 양수,정수를 판별하는 0,1을 넣고,

정수부엔 실수의 정수부분을 넣고, 소수부엔 실수의 소수부분을 넣는다.

 

10진수의 소수를 2진수의 소수로 표기할땐 x2를 계속 진행하면서, 정수부분을 별도로 떼고 0이 될때까지 반복한다.

 

10진수의 소수 7.625를 2진수의 고정 소수점으로 표기하면,

7을 별도로 빼두고 0.625를 변환

 

0.625 x 2 = 1.25  <- 1

0.25 x 2  =   0.5  <- 0

0.5 x 2    =   1.0  <- 1

 

위에서부터 정수부분을 뗀 것을 소수점이하로 붙이면 된다.  0.101

별도로 빼두었던 7을 2진수로 변환하면

111.101이 된다.

양수이기때문에 부호비트를 0으로 해주고, 빈 부분은 0으로 채워준다.

 

부동 소수점(Floating point)

부동소수점은 고정소수점에서 약간의 정규화 과정을 거친 것이다.

위에서 실수형은 부호,지수,가수로 이루어졌다고 했는데, 부동 소수점을 뜻한것이다.

 

2진수를 

1.xxxxxx   x   2^n 의 형태를 취한 것이 부동소수점이다.

 

위에서 봤던, 111.101을 예시로 들면 오른쪽으로 2칸 민 형태로 바꾼 후 x 2^2을 해준다.

 

고정소수점 111.101 -> 부동소수점 1.11101 x 2^2

 

32비트의 float에선,

1비트를 부호비트 8비트는 지수부, 23비트를 가수부로 쓴다.

 

가수(Mantissa)부

실제 값인 가수를 저장하는 부분으로 1.xxxxx 부분이 저장되는 공간을 뜻한다.

float(32비트) 기준 23bit가 가수부이고, 2진수 23자리는 10진수로 약 7자리 저장할 수 있는데, 이것이 float의 정밀도가 된다.

 

지수(Exponent)부

지수부는 2^n부분을 저장하는 공간이다.

32비트 기준으로 지수부는 8bit로 256개의 값을 저장할 수 있고, 지수엔 부호가 있으므로 '-127 ~ 128'의 값이 저장된다.

 

2진수로 저장되기에 0~255로 생각하면 되고,

이중에서 0과 255는 '숫자 아님(NaN)' 이나 '양의 무한대', '음의 무한대'와 같이 특별한 값을 표현하기 위해 예약되어 있다.

 

그래서 127을 기준으로 지수의 음수와 양수가 갈린다.

기준점을 bias라고 부른다. ( 0 = 숫자아님, 1~126 = 음수, 127 = 2^0, 128~254 = 양수, 255 = 무한대)

 

위에서의 1.11101 x 2^2 를 2진수로 표현하면 아래와 같다.

부동소수점의 이름 유래(?) & float 과 double

더보기

소수점을 이동한다는데서 부동을 따와서 부동소수점인듯 싶다.(타 블로그 참조)

 

부동 소수점에서 floating을 따와 float을 만들고,

float에 2배에 해당하는 게 double type이라고 생각하면 된다.

 

참조

'Java의 정석' 책

타블로그 참조

댓글