본문 바로가기
  • 시 쓰는 개발자
CS 개념/기타 개념

부동소수점

by poetDeveloper 2022. 10. 17.

부동 소수점(浮動小數點) floating point

 

- 십진법

우리가 쓰는 표현은 decimal number, 10이 기준이 되는 표현방식이다.

- 이진법

2를 기준으로 설명하게 된다. 정확히는 이진법 10(2)을 기준으로 생각하는 것. 이진법에서는 0.12개 가져다 놓으면 이는 1.0이 된다.

 

십진유한소수점수, “십진무한소수점수

유한소수점수 : 말 그대로 소수점이 유한, 3/4, 0.2 등 분모에 적당한 자연수 값을 곱하면 10의 거듭제곱 꼴이 된다.

무한소수점수 : 0.3같은 경우 10으로 계속 나눠도 완벽하게 갈라지지 않아서 이는 0.33333....이 된다.

 

이진: 유한소수점수, ”이진무한소수점수

무한소수점수 : 대표적으로 십진수 0.1이 이진무한소수점수 이다. , 딱 떨어지는 0.1을 이진수로 표현할 수 없다는 뜻.

이진수 0.1은 십진수 0.5이다.

절반씩 쪼개가면서 십진수 0.1이 나오게끔 생각해본다. (표)

0.1을 찾기 위해 반씩 쪼개면서 근접해가는 과정

 

1/10의 분모 10에 어떤 수를 곱하더라도 2의 거듭제곱꼴로 표현할수 없으므로 이를 이진수로 표현할 수 없다는 것. , 10진수 0.5 0.25 0.125 0.0625들의 합으로 0.1을 표현할 수 없다는 뜻.

 

float 32bit 저장방식

그래서 컴퓨터에는 무한 숫자를 저장할 수 없으므로 32bit 저장공간에 무한소수를 욱여넣고, 나머지 수는 생략하게 됨. 0.1=0.000110011001100110011001100110011001100.... 이지만 생략해서 0.1으로 그냥 표현해주는 것,

저장공간이 float32bit, double64bit인데 32bit중에 1bit+ - sign bit 즉 부호비트이고, 8bit는 지수부(exponent)이고 남은 23bit로 수를 표현한다.

 

그래서 우리가 위 표를 계속 채워가서 23bit짜리 십진수 0.10000000149011611938 이라는 수를 얻었다면 이는 표현 가능한 범위 내에서 가장 정확한 표현일 것이다.

 

0.1 x 0.1 != 0.01

그럼 이를 2번 곱하면 0.01이 나올까? 일단 0.1 자체가 정확한 표현이 불가능하므로 당연히 0.01또한 안나오겠지만, 얼마나 근접한지를 살펴본다. 위에서 23bit 십진수를 제곱하고 23bit까지로 반올림 하게 되면 0.01000000070780515671이 나오는데 놀랍게도 이는 0.01과 가장 근접한 23bit 이진소수점수가 아니다. 0.01과 가장 근접한 수는 0.00999999977648258209이다.

 

따라서 우리가 컴퓨터에 0.01을 직접 입력하게 되면 0.01과 가장 근접한 0.00999~~~ 가 입력되므로 0.1 x 0.1 == 0.01을 하게 되면 False가 나오게 되는 것이다.

 

왜 굳이 이진법으로 변환?

그렇다면 왜 이진법으로 굳이 변환해야 하는가?를 생각해보면, 애당초 Floating Point가 아주 큰 수나 아주 작은 수를 효율적으로 연산하기 위해 만들어진 것이기 때문이다. CPU는 연산을 할 때 ALU(Arithmetic logic unit)에서 하지만, 소수점수 연산을 할때는 ALU의 일부인 전문 소수점 수 처리부 FPU(Floating Point Unit)에서 처리하게 된다. 미세하지 않은 값을 계산하는 것은 하드웨어적으로 효율이 좋지 않고 소프트웨어적으로도 충분히 가능하다.

 

정밀도 문제

그렇다보니 Floating Point는 정밀도 문제(precision problem)가 항상 따라다닌다. 하지만 계산기 앱이나, 은행같이 정밀한 계산이 필요한 곳에서는 이런식의 근사치 계산이 아닌, 정수를 여러개 묶어서 십진 계산을 하기 때문에 우리가 걱정하는 일은 일어나지 않는다.

 

컴퓨터에서 소수점수를 보통 실수라고 표현하곤 하는데, 틀린건 아니지만 엄밀히 말하면 float는 무리수를 저장할 수 없으므로 수학적으로 실수가 아님. 그래서 전공자들은 보통 float라고 하기도 함.

 

해결법

python을 기준으로 말해보면 decimal 모듈을 import해 사용하면 가장 깔끔하게 해결할 수 있다. decimal.Decimal(‘0.1’)이라고 하면 0.1을 온전히 표현할 수 있다. 그 외의 방법으로는 math.fsum() 이나 round(), float.as_integer_ratio(), math.is_close() 등을 사용한다.

 

느낀점

부동소수점은 1학년 때 C언어를 배우면서 초반의 복병같은 존재인데, 컴퓨터 구조와도 연결되는 상당히 중요한 개념이다. 조금 포괄적으로 정리했는데, 나중에는 더 구체적으로, 그리고 좀더 이해하기 쉽게 정리해봐야겠다.

'CS 개념 > 기타 개념' 카테고리의 다른 글

프레임워크와 라이브러리의 차이  (0) 2023.02.18
클라이언트와 서버의 차이점  (0) 2023.02.18
쿠키와 캐시  (0) 2022.12.09