0.1 + 0.2 = 0.3이 아니다?
코딩을 한창 재미있게 배우다가 어랏? 하게 되는 지점이 있습니다. 바로 '소숫점 계산'과 관련한 내용입니다. 일단 브라우저 console 창에 0.1 + 0.2를 실행해보시기 바랍니다. 원하는 결과를 확인할 수 있나요?
뭐라고라고라? Javascript 한테 다시 한번 물어보겠습니다.
0.1 + 0.2가 0.3과 같냐고 물어보니, 아니라고(false) 대답해줍니다. 뭐라고라?
내 머릿속에서는 0.3이라고 하는데, 컴퓨터는 0.30000000000000004라고 알려줍니다. 이게 어떻게 된 일 일까요?
다른 소수들을 가지고도 한번 테스트를 해보도록 합시다.
이런 계산 결과가 나온다는게 이상하기도 하고, 뭔가 좀 신기하지 않습니까?
컴퓨터는 원래 그렇게 계산해준다
곰곰히 다음 사실을 잘 생각해보면 이해가 갈듯 말듯 하게 되는데요, 컴퓨터는 전기가 통하느냐 아니냐라는 1과 0으로 동작하기 때문입니다. 즉, 2진수로 동작한다는 것이죠.
우리가 익숙한 10진수 숫자들도 컴퓨터가 계산할 때는 모든 숫자들을 2진수로 만들어서 계산을 해주게 됩니다. 원래 그렇게 동작하도록 만들어져 있습니다.
10진수와 2진수를 살펴봅시다
몇 개의 10진수 숫자들을 2진수로 바꿔봅시다.
10진수 : 2진수
1 1
2 10
3 11
4 100
5 101
6 110
소숫점을 가지는 10진수 숫자들을 2진수로 바꿔봅시다.
10진수 : 2진수
1 0.0001100110011001100110011001100110011001100110011001101....
2 0.001100110011001100110011001100110011001100110011001101.....
3 0.010011001100110011001100110011001100110011001100110011.....
4 0.01100110011001100110011001100110011001100110011001101......
5 0.1
6 0.10011001100110011001100110011001100110011001100110011......
10진수 5는 2진수로 변환할 때, 나머지 없이 딱! 떨어지지만 나머지 숫자들은 무한히 반복되는 무한 소수가 됩니다. 컴퓨터 메모리는 유한하기 때문에 무한한 값을 담을 수는 없어서 적당한 길이에서 결과값을 끊어주는 것 뿐입니다.
따라서 0.1 + 0.2를 컴퓨터가 2진수로 계산을 할 때는 결국 아래와 같이 계산을 하게 됩니다.
0.0001100110011001100110011001100110011001100110011001101(2) //무한소수인데 유한소수 형태
+ 0.001100110011001100110011001100110011001100110011001101(2) //무한소수인데 유한소수 형태
--------------------------------------------------------------
0.00121012101210121.......(2)
무한히 반복되는 2진수를 적당한 위치에서 반올림해서 끊어준 값으로 계산을 한 후
다시 10진수로 변경을 해주면 그 값이
0.30000000000000004 (10) 이 되는 것입니다.
(물론 이런 계산방식은 이해를 위해 예시로 드는 계산방식입니다. 컴퓨터의 연산방식과 100% 동일하지 않음)
모든 프로그래밍 언어는 소숫점을 가진 계산을 유의해야 한다
Javascript 뿐만 아니라, 파이썬, 자바, C# 등 모든 프로그래밍 언어들은 결국 '컴퓨터'를 이용해서 계산을 하기 때문에 동일한 이슈지점을 가지고 있습니다.
여기서, 머릿속에 넣어두고 기억하고 있어야 할 부분은 바로 이것입니다.
소숫점 계산을 가지고 있는 프로그램은, 코딩할 때 유의해야 한다.
왜냐하면, 소숫점 계산에 대한 오류로 인해 의도하지 않은 결과가 튀어나올 수도 있고, 가격을 매기거나 해서 실제 판매가 일어나는 사이트이거나, 세금을 계산하거나 하는 경우에 이런 오류가 발생한다면 큰일이겠죠?
물론, 이를 해결하는 매우 다양한 방식들이 이미 존재합니다.^^
아주 간단한 알고리즘(?) 사례로는 이러한 것들도 존재합니다.
<script>
const num1 = 0.1;
const num2 = 0.2;
function sum(num1, num2) {
const newNum1 = num1 * 10; //10을 곱해서 소숫점을 없애줌
const newNum2 = num2 * 10; //10을 곱해서 소숫점을 없애줌
const result1 = newNum1 + newNum2; // 10진수 상태로 덧셈 진행
const result2 = result1 / 10; // 처음 곱했던 10이 있으니 다시 10으로 나누어줌
return result2;
}
console.log(sum(num1, num2));
</script>
사람들의 반짝반짝 빛나는 아이디어가 돋보이지 않는가요?
굳이 이름을 붙여 본다면, '소숫점 계산 오류를 제거하는 알고리즘'으로 불릴 수도 있어 보입니다.
마치며
물론 모든 컴퓨터 언어에는 이러한 문제를 해결하는 라이브러리나 기능함수들이 이미 개발되어 있습니다.^^
크게 걱정할 이슈는 아니지만, 컴퓨터가 어떻게 동작하고 계산하는 지에 대한 방식은 이해를 해두는 것이 좋기 때문에 정리를 한번 해보았습니다.
뭐가 이 따위야?라는 생각보다, 오호~ 신기한 지점인데?라는 호기심이 스친다면, 코딩공부를 해나가는 게 훨씬 더 즐거운 일이 될 것입니다.
컴퓨터의 세계는 참으로 신기한 현상 투성이입니다.^^
오늘도 즐거운 코딩하세요!
즐거운 코딩생활, 즐코딩.
KINcoding.
'Javascript' 카테고리의 다른 글
마우스 wheel 동작 이벤트 및 감지 - scrollY, scrollTop 차이? (0) | 2023.02.09 |
---|---|
소수점 계산 시 정확한 계산 결과를 위한 적용 방법 (0) | 2023.02.08 |
JS function 문법 기초 정리 (0) | 2023.02.03 |
SEO 최적화를 돕는, 이미지 Alt 속성에 Hypen 자동으로 넣기 (0) | 2023.02.02 |
Carousel을 직접 만들어 보자 Part 2 - 성능 향상 하기 (0) | 2023.01.29 |
댓글