영어 공부겸 Medium의 개발 블로그를 탐방하던 도중에 이런 포스트를 찾았습니다. 그리고 최근 개발 커뮤니티의 cs 질문 게시판에서 비슷한 주제의 질문이 보였습니다.
" 이 코드는 왜 false가 나올까요? "
console.log(0.1 + 0.2 === 0.3);
먼저 떠오른 대답은 "컴퓨터는 실수를 정확하게 저장할 수 없다." 였습니다. 하지만 이어지는 "그럼 왜 정확히 저장할 수 없나요?"라는 질문에는 정확히 대답을 할 수 없었습니다. 그래서 이렇게 된 김에 제대로 공부해보려고 합니다.
사전지식. 컴퓨터에 저장되는 실수의 형태
컴퓨터는 모든 데이터를 bit를 사용해 2진수의 형태로 저장합니다. 따라서 실수를 저장할 때도 다음 예시처럼 2진수로 바꿔서 저장합니다.
컴퓨터가 실수를 "정확하게" 표현할 수 없는 이유
위에서 설명했듯이, 컴퓨터는 실수를 이진수의 형태로 저장합니다. 그러나 모든 실수가 이진수로 정확하게 변환되지 않습니다. 이유는 실수중 일부가 이진수로 변환되는 과정에서 무한 소수가 되기 때문입니다.
다음 그림은 컴퓨터가 0.1을 저장하고 출력하는 과정입니다. 이를 통해, 컴퓨터에 저장되는 값은 0.1 가까운 값이지 정확한 0.1은 아니라는 것을 알 수 있습니다.
위 내용을 바탕으로, " 그럼 왜 정확히 저장할 수 없나요? "라는 질문에 대해 답하면 다음과 같습니다.
컴퓨터는 실수를 이진수로 변환해서 저장하는데,일부는 무한소수로 변환됩니다.
하지만 컴퓨터는 자원이 무한하지 않기 때문에 이를 정확히 저장할 수 없습니다.
"정확하지 않은" 값 출력해서 확인해보기
이제 실제 코드와 출력을 통해 저장된 0.1과 0.2의 값 확인해보겠습니다.
(참고로 아래 저장된 근사값은 double(64비트)에 저장된 근사값입니다.)
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
double value1 = 0.1;
double value2 = 0.2;
// BigDecimal로 double 값의 근사값 출력
BigDecimal approx1 = new BigDecimal(value1);
BigDecimal approx2 = new BigDecimal(value2);
System.out.println("0.1의 근사값 (double): " + approx1.toPlainString());
System.out.println("0.2의 근사값 (double): " + approx2.toPlainString());
}
}
추가 의문 : 0.1과 0.2 의 합
하지만 이상합니다.
두 값을 더하면 대충 0.300000000000000016~이고,이를 반올림하면 0.30000000000000002인데 왜 합을 출력해보면 0.30000000000000004가 출력될까요?
그 이유는 '사전지식'에서 말했듯 컴퓨터는 모든 데이터를 2진수로 저장하고 사용하기 때문입니다. 즉 덧셈 또한 2진수로 진행됩니다. 따라서 2진수 덧셈 결과를 10진수로 변환하면 0.30000000000000004을 얻을 수 있습니다.
- 10진수 덧셈 : 0.100000000000000005~(0.1) + 0.200000000000000011~(0.2)
- 2진수 덧셈(실제 진행되는 덧셈) : 0.0001100110011001~(0.1) + 0.00110011001100110~(0.2)
Next
생각보다 내용이 길어져 나머지는 다음 포스트에서 다루겠습니다.
다음 포스트 내용
- 찾아보면서 자주 보였던 IEEE 754 표준이란?
- BigDecimal 클래스는 어떻게 정확하게 실수를 저장하지?
- 왜 System.out.println(0.1)의 출력은 그대로 0.1이 나오지?
End.
참고자료
'CS' 카테고리의 다른 글
URI vs URL vs URN (0) | 2025.04.14 |
---|---|
REST API에서 "REST"의 의미 (0) | 2025.04.12 |
SOLID원칙의 간단한 정리 (0) | 2024.06.23 |
C언어의 컴파일 과정 (1) | 2023.12.22 |
소켓이란? (0) | 2023.12.19 |