둘셋 개발!

[Java] float의 지수부분(8bit)는 왜 범위가 -127~128 일까 본문

카테고리 없음

[Java] float의 지수부분(8bit)는 왜 범위가 -127~128 일까

23 2024. 5. 25. 14:04

Intro.

float를 2진수로 저장하는 방식을 보다가 지수부분(8bit)의 범위가 왜 -127~128인지 궁금해졌다. 

왜냐하면 8bit일 경우, 2의 보수법을 사용하면 -128 ~ 127까지 이기 때문이다.


우선 float의 값을 2진수로 변환하는 예시를 하나 들어보자.

 

float num = (float) 263.3;

 

 

이 값을 실제로 메모리에서는 어떻게 저장할까?

 

float는 4byte를 차지하기 때문에 총 32bit로 263.3를 표현해야 할 것 이다. 

그리고 자바에서 실수형을 저장할 때 부동소수점으로 표현함으로 32bit를 부호비트, 지수비트, 가수비트로 표현할 것이다.

(부동소수점이 무엇인지 모르신다면 더보기를 열어보세요)

더보기

실수형을 표현하는 2가지 방식

 

(1) 고정소수점

정수부분과 소수 부분을 나누어 각각 고정된 위치에 저장한다.

예를 들어 1111.0001(2)를 저장하려고 하면 1111(정수부분),  0001(소수부분)를 각각 저장한다.

소수점이 고정된 채로 저장한다고 생각하면 된다.

 

(2) 부동소수점

지수와 가수로 나누어서 저장한다.

예를 들어 1111.0001(2)를 저장하려고 하면 M * 2^(E) 형태로 저장하려고 한다.  (M: 가수, E: 지수)

float 타입 표현 방식 (출처: 모두의 연구소)

 

263.3을 부동소수점으로 표현하면 다음과 같은 과정을 거친다.

일단 263.3은 10진수니까 2진수로 바꾼다.

 

100000111.010011001......(2)

 

그리고 M * 2^(E) 형태로 만들어주기 위해 정규화 과정을 거친다.

정규화 과정은 별게 아니라 정수부분에 1만 남기게 하는 것이다.

근데 지금 정수부분에 100000111이 있으니까 맨 앞의 1만 남기고, 나머지 00000111은 소수부분으로 이동시켜줘야 한다.

1.00000111010011001......

그렇게 되면 소수점이 앞으로 8칸 갔으니까 2^8를 곱해줘야 같아진다.

 

1.00000111010011001........ * 2^8

 

지수 8이 되었고 가수는 00000111010011001 이 되었다.

이제 32bit에 부호, 지수, 가수를 각각 넣어주면 된다!!

 

부호비트는 양수이므로 0

가수비트는 000000111010011001

지수비트는 8에 편향값을 더해준 값인 10000111 

 

왜 지수비트는 편향값을 사용하는 것일까..??!?!!??

보통 부호있는 값을 저장하려고 할 때 2의 보수법을 사용하는데........

 

지수표현에 2의 보수법을 사용하지 않는 이유

8비트로는 부호가 있는 숫자를 표현해야 하니까 2의 보수법을 사용하면 -128 ~ +127 까지 표현할 수 있다.

2의 보수법을 사용하면 지수가 0이라면 0000 0000으로 표현할 것이다.

그런데 이렇게 하면, 메모리에 저장된 00000000 00000000 00000000 00000000을 float값으로 꺼내올 때, 1이 되어버리는 이상한 현상이 발생한다.

왜냐하면 맨 앞의 1비트는 부호비트이니까 양수라고 해석하고, 중간의 8비트는 지수부분이고, 나머지 23비트는 가수부분이니까

+ 1.00000000000000000000000 * 2^0 이렇게 계산 할 것이다.

이 값은 1이다.

모든 비트가 0인데 10진수로는 1이 되어버리는 것이다.

 

반면, 편향된 값을 사용하면 이 이상한 현상을 마주하지 않을 수 있다.

 

편향값을 사용하는 방법

편향값 사용 공식

만약 8비트에 편향값을 사용하면 공식의 k에 8을 넣으면 된다.

2^(8-1)-1   =   2^7-1   =   128 - 1 = 127

즉, 8비트일 경우 편향값이 127인 것이다.

8비트의 편향값 (출처: https://devocean.sk.com/blog/techBoardDetail.do?ID=165276)

여기서 의문이 들것이다.

32비트 모두 0이면 + 1.0000000000000000000000 * 2^-127 이기 때문에 이것도 0이 아니지 않냐는 의문....

0에 가까운 숫자이지만 0이 아니다.

 

이때는 subnormal number 규칙에 의해 0이 만들어진다.

만약 지수부분이 모두 0이라면 가수부분을 0으로 두고, 지수부분을 -126으로 한다.

이렇게 되면 0을 만들 수 있다.

추가적으로 0과 2^-126의 사이의 더 작은 값을 표현할 수 있게 되었다.

예를 들어 지수부분이 모두 0이고, 가수부분이 00000000000000000000001 일 경우

0.00000000000000000000001 * 2^-126 =  0.000000000000000000000000000000000000000000000000.................0000(대충0이 148개)1

인 값을 표현할 수 있다.

 

이제 지수비트에 2의 보수법을 사용하지 않고 다른 방법인 편향값을 사용한다는 것도 알았고,

편향값을 사용했을 때의 장점도 알았고,

편향값을 얼마로 사용해야할지도 알았다.😃


결론

부동소수점의 지수의 범위가 -127 ~ 128인 이유는 편향된 지수를 사용하기 때문이다~


ref.

https://modulabs.co.kr/blog/floating-point-biased-exponent/

 

부동소수점 편향된 지수 Biased Exponent

32비트 부동소수점을 표현시 사용하는 편향된 지수를 (biased exponent) 사용하는 예시를 살펴보며, 편향된 지수 사용시 장점을 설명합니다. 추가적으로 지수 사용의 예외 경우도 설명합니다.

modulabs.co.kr

https://devocean.sk.com/blog/techBoardDetail.do?ID=165276

 

부동 소수점의 이해 (2부)

 

devocean.sk.com