감자는 아직 꿈을 꾼다.

[컴퓨터 구조 - 부록] 부동 소수점 본문

CS적 감자/컴퓨터 구조 & 운영체제

[컴퓨터 구조 - 부록] 부동 소수점

dreaming-potato 2024. 11. 22. 00:36

 

AI가 생성한 소수 이미지

✏️부동 소수점과 고정 소수점

 

컴퓨터는 실수를 표현할 때 소수점의 위치 고정 여부로 고정 소수점과 부동 소수점으로 나눕니다.

고정 소수점은 소수점의 위치가 고정되어 있는 표현법

부동 소수점은 소수점의 위치가 고정되어 있지 않고 이동하며, 따로 위치를 나타내는 수를 적는 표현법입니다.

 

이렇게 말해선 이해가 가지 않을 수도 있으니 예시로 확인해보죠.

 

그전에 십진수 소수를 이진수로 표현하는 방법에 대해서 말해보면 

13.625라는 십진수를 이진수로 표현하려면 정수부분인 13을 이진수로 변환하고, 나머지 0.625를 이진수로 변환 시키고

둘 사이에 소수점을 찍어서 이어주면 끝입니다. 

0.625는 어떻게 이진수로 표현하냐면 단순하다 2를 곱하고 정수 부분을 쓰고, 남은 소수 부분이 0으로 나누어 떨어질때 까지 반복해서 계산합니다.

 

0.625 x 2 = 1.25 -> 1 , 나머지 0.25

0.25 x 2 = 0.5 -> 0 , 나머지 0.5 

0.5 x 2 = 1.0 -> 1 , 나머지 0  끝 !! 

이렇게 13-> 1101과 이어주면 1101.101 이렇게 표현됩니다. 

 

1101.101이라는 소수 표현은 고정 소수점과 부동 소수점 각 각 다르게 저장됩니다.

32비트 기준으로 각각 설명하겠습니다.


🎭고정 소수점 

 

고정소수점 - 그림 허접해서 죄송합니다

고정 소수점에서는 MSB(가장 왼쪽의 비트)가 부호비트로 사용되고 0 : 양수 , 1 : 음수 입니다.

또한 32비트 기준으로 정수부가 15비트, 실수부가 16비트로 표현됩니다.

정수부는 1101을 그대로 쓰면 되고, 실수부는 101을 바로 이어서 씁니다.

보시기에도 소수점의 위치가 고정되어 있는 것을 보실수있죠.

그렇기에 구현이 편합니다. 하지만 정수부가 15비트. 실수부가 16비트로 수를 표현할 수있는 범위가 작습니다.

실수부를 표현하는 범위도 적기에 소수점 자리수를 표현하는 범위가 작아서 정밀도도 떨어집니다.

그래서 저희가 프로그래밍언어를 사용할 때는 대부분 사용하지 않습니다.

 

✨부동 소수점 

부동 소수점

 

그림은 IEEE 754 규정의 부동 소수점 표현입니다.

MSB가 부호비트, 지수부는 8비트. 가수부는 23비트로 구성되어 있는 데

여기서 지수부와 가수부에 대해 설명하기전에 부동 소수점 표현을 하기 위해서는 정규화 과정을 거쳐야합니다.

위의 13.625를 1101.101 이진수로 변환하고 그것을 다시 부동 소수점으로 표현하기 위해서는 

1.xxxxxxxx * ( 2 ^ E ) 꼴로 변환해야합니다. ( 여기서 E는 소수점을 이동시킨 칸입니다 )

1101.101에서 1전까지 소수점을 이동시키는 거죠, 그래서 소수점의 위치가 떠다니면서 움직이기에 Floating Point 인것입니다.

1.101101 * (2 ^ 3) 여기서 3칸 소수점을 이동했기에 E = 3이 됩니다. 

위에 표현한 꼴로 정규화를 시키면 항상 앞은 1일 것입니다. 그렇기에 1을 버리고 소수점 아래만 가수로 취합니다.

여기서 가수부는 1이하의 소수점 숫자들 101101입니다. 

지수부는 130이고요. 왜 3이 아니라 130이냐면 Bias인 127을 더해줬기 때문입니다.

 

🥸Bias

 

그냥 3을 8비트로 표현하면 문제가 됩니다. 왜냐면 음수 표현이 불가능해지기 때문입니다.

예를 들어서 0.00101 이라는 십진수를 부동소수점 표현으로 하면 1.01 * ( 2^ - 3) 입니다.

위처럼 3을 8비트인 00000011로 표현하면 -3 표현이 안되는 문제가 발생하기에 여기서 Bias를 더해주는 것입니다.

 

지수부 : 8비트 0 ~ 255 

1 ~ 127 : 음수 

128 ~ 254 : 양수 

 

이렇게 표현되는 것이죠 

0과 255는 포함되지 않았습니다. 그 이유는 0은 0을 표현하고, 255는 가수부가 0이냐 아니냐에 따라서 무한대 or NaN을 나타내기 때문입니다. ( 자세한 부분은 Normalized Value , Denormalized Value로 검색해보시는 걸 추천합니다 ^^  )

 

부동 소수점에서 32비트는 Single - Precision , 64비트는 Double - Precision이라고 합니다.

64비트는 1비트의 부호비트, 11비트의 지수부, 52비트의 가수부로 구성되어있습니다.

이렇게만 봐도 고정 소수점보다는 훨씬 더 많은 범위의 수를 저장할 수있고 정밀성 또한 더 높아서 부동 소수점을 사용합니다. 그렇지만 완벽하게 정확하게 소수를 저장하는 것은 아닙니다.


😜오차는 존재한다.

지금까지 내용을 배운 이유입니다.

0.1 곱하기 0.1은 0.01입니다. 그러면 0.1 * 0.1 == 0.01 은 True일까요?

아닙니다.

이를 자바에서 실행시켜봤습니다.

🪟오차 생기는 이유 

0.1은 사실 정확한 0.1로 저장되지 않고 무한 소수로 표현될 것입니다.

위에서 설명한 이진수로 표현할 때 2의 N승 분의 1로 표현되지 않으면 나머지가 0이 되지않아서 무한 소수로 계속 붙게 되는 거죠.

정확히 0.1000000014901161193847656256로 32비트에선 표현됩니다.

이렇게 오차가 발생하므로 0.1 * 0.1 은 0.01이 아니게 되는 것입니다.

오차가 발생하고, 우리가 저장한 소수 숫자가 실제론 정확한 값이 아닌 것을 아는 것은 매우 중요합니다.

 

이러한 오차가 계속해서 쌓이게 되면 유의미하게 부정적인 결과를 발생시키기 때문입니다.

실제로 미사일 시스템을 이러한 오차를 무시하고 개발하여, 잘못 발사되어 아군이 사망하는 사건도 발생했습니다.

또한 금융 시스템에서도 중요하겠죠? 

 

그래서 정확히 소수 표현을 하고 싶을 땐 라이브러리를 사용하는 게 좋습니다.

자바에서의 정확한 소수를 표현하는 라이브러리 BigDecimal을 사용한 코드를 보여드리겠습니다.

Same이라고 정확히 출력되는 모습을 볼 수 있습니다.


 

그러면 왜 부동 소수점으로 저장하는 거지 ??

 

이는 자료형의 존재 이유와 같습니다.

자료형은 데이터의 범위에 따라서 Byte수를 다르게 할당하여 메모리를 효율적으로 쓰게 해준 것이고,

점수가 1~ 100 이라면 굳이 int형을 쓸게 아니라 Byte형을 사용하여 쓰는 것이 효율적입니다.

 

컴퓨터는 수많은 데이터에 대해서 연산을 해야되고 메모리를 효율적으로 사용해야 되기 때문입니다.

 


 

이렇게 오차가 발생하는 것을 인지하고 개발하는 걸 본적은 저의 부족한 프로젝트나 인턴 경험 속에서 없었습니다.

하지만 이런 부분을 알고 고려하는 것이 좋은 개발자로 성장하기 위한 것 같습니다.

 

더 깊게 다룰수도 있었지만 그 정도까지는 시스템 프로그래머가 아닌 이상은 괜찮을 것 같아서 여기까지만 다뤘습니다.

저도 기억이 잘 안나기도하고요 ㅎㅎ