자바스크립트 숫자 타입 주의점
오늘 프로그래머스에서 9로 나눈 나머지를 풀이할 때 스터디원분이 특이점을 발견하셨다.
https://school.programmers.co.kr/learn/courses/30/lessons/181914
해당 문제의 입출력 예시 2번을 보면 이렇게 써있다.
예제 2번의 number는 78720646226947352489으로 각자리 숫자의 합은 101입니다. 101을 9로 나눈 나머지는 2이고, 실제로 78720646226947352489 = 9 × 8746738469660816943 + 2입니다. 따라서 2를 return 합니다.
그래서 78720646226947352489을 9로 나눈 즉, 코드 Number('78720646226947352489' % 9)실행해서 직접 답을 구해보려고 했으나 실패했다.
그 이유는 숫자가 너무 크기 때문에 64비트의 공간이 부족하여 정확한 숫자를 처리하지 못하여 생기는 오류였다. 검색에 의하면 자바스크립트는 숫자 타입의 값을 생성할 때 배정밀도 64비트 부동소수점 형식을 사용하기 때문에 이런 에러가 발생하고 정확하지 않은 숫자가 계산된다고 한다.
실제로 구글 크롬 개발자 도구 콘솔에 78720646226947352489를 입력하면 반환되는 숫자도 달랐다.
이러한 에러는 실무에서도 직접 경험해볼 수 있으면서 자바스크립트에서 가장 기본 중의 기본이 되는 개념이기 때문에 확실하게 정리를 하려고 한다.
나와 같은 비전공자 문과 입장에서는 '배정밀도는 무엇이고, 64비트는 무엇이며, 부동소수점 형식 무엇인가'라는 생각이 든다. 🤔
그러므로 이 단어 하나하나를 파헤쳐보면서 이에 대해 이해하려고 한다.
배정밀도란?
배정밀도는 부동소수점 숫자의 정밀도를 나타내는 용어이다. 배정밀도는 실수 값을 더 정확하게 나타낼 수 있는 더 높은 정밀도를 제공한다. 간단하게 말하자면, 배정밀도는 더 정확한 실수 표현을 위하여 64비트를 사용하는 것을 의미한다.
64비트란?
64비트란 컴퓨터에서 데이터를 처리하는 데 사용되는 비트(bit)의 수이다. 비트는 컴퓨터에서 정보를 저장하고 표현하는 최소의 단위이며, 0 또는 1의 값을 가진다. 이진수로 표현할 때 2의 64승(18,446,744,073,709,600,000)인 매우 큰 숫자의 범위를 나타낼 수 있다. 10진수로 표현하면 대략 18 백십 경에 해당한다.
부동소수점이란?
부동소수점은 컴퓨터에서 소수를 표현하는 방식이다. 소수는 소수점 아래에 있는 숫자, 2.5나 9.21와 같은 숫자를 의미한다.
부동소수점은 실수를 두 부분으로 나누어서 표현한다. 첫 번째 부분을 가수라고 한다.
가수는 실제 숫자 값을 저장하는 역할을 한다. 가수는 이진수로 표현이 되며, 소수의 정확도와 정밀도에 영향을 준다.
이진수로 표현을 하는 것은, 예를 들어 0.75를 이진수로 변환한다면,
1. 0.75를 2로 곱한다.
- 0.75 * 2 = 1.50
- 정수 부분인 1을 얻는다.
2. 소수 부분 0.50을 다시 2로 곱한다.
- 0.50 * 2 = 1.00
- 정수 부분 1을 얻는다.
3. 0.00이 되면 계산을 종료한다.
위와 같은 과정을 반복한다. 소수 부분을 2로 곱하고, 그 결과로 정수 부분을 얻는다. 계속해서 점점 0.0..,0.00..,0.000.., ... 형태로 수렴한다. 따라서 0.75를 이진수로 변환하면 0.11이 된다. 그리고 이것을 가수라고 한다.
부동소수점의 두 번째 부분은 지수라고 한다. 지수는 숫자의 크기와 소수점의 위치를 나타낸다. 그러므로 방금의 예시에서 지수는 2이다.
계산이 멈춘 시점(0.00)에서 소수점을 오른쪽으로 2번 이동시켰으므로 지수는 2가 된다.
결론
결론적으로 말하자면 78720646226947352489와 같이 너무나 큰 숫자를 이진수로 변환할 때 무한히 숫자가 0으로 수렴하지 않는 일이 발생하여 컴퓨터 에러가 발생하는 것이다. 이러한 일이 발생하기 때문에 자바스크립트에서는 64비트로 처리가 불가능한 숫자인 78720646226947352489를 Number로 변환할 때, 78720646226947360000으로 올림으로 자동 처리하는 것이다. 그리고 이러한 에러는 정밀도 손실이라고 부른다. 이러한 경우를 항상 주의하면서 숫자 타입의 반환 코드를 작성해야함을 유의하자.
출처
1. 숫자형 https://ko.javascript.info/number#ref-387
숫자형
ko.javascript.info
2. chatGPT: chat.openai.com
'JS > 이론' 카테고리의 다른 글
에러 처리 구현(1): try ... catch ... finally 문 (0) | 2023.05.29 |
---|---|
addEventListener의 'keyup', 'keydown', 'keypress'의 차이 (0) | 2023.05.20 |
자바스크립트 정리 #1 (0) | 2023.05.16 |