0.1 + 0.2 !== 0.3

남성윤·2023년 1월 13일
0

학습 일지

목록 보기
10/369

개요


프로그래밍에서의 숫자에 대해 공부하다 보면, 크롬 개발자 도구 등에서

0.1 + 0.2 === 0.3

다음과 같은 식을 입력했을때, false라는 결과를 내주는 것을 볼 수 있다.
이는 컴퓨터가 데이터를 저장하는 방법에서 기인하는 문제인데, 이에 대해서 알아보려고 한다.

컴퓨터는 2진법, 사람은 10진법!


결론부터 말해서, 0.1 + 0.2 !== 0.3 문제는 컴퓨터가 2진법을 사용하기 때문에 발생하는 문제이다.
정수체계에서는 2진법으로 표현하더라도 모든 숫자가 딱 떨어지지만, 소수로 내려간다면 이진법으로 변환했을 때, 무한소수가 되어버리는 경우가 있다.
이러한 무한 소수를 메모리의 한계 내에서 저장해놓으려면 근사값으로 저장할수밖에 없는데, 이런 증감이 겹치다보면 계산상의 오류로 발생하게 되는 것이다.

그럼 소수 계산은 어떻게 해?


크게 두가지의 해결방안이 있는데, 계산하는 소수점자리까지만 표기하는 방법과, 정수로 변환하여 계산한 뒤 다시 소수로 되돌리는 방법이다.

1. toFixed() 사용


첫번째 방법인 계싼하는 소수점 자리까지만 표현하는 방법이다, toFixed()메서드는 입력한 자릿수에 맞춰 반올림해주는 메서드로,

0.1.toFixed(1) // '0.1'
0.1.toFixed(2) // '0.10'
0.16.toFixed(1) // '0.2'

단, 이 toFixed()메서드 자체도 몇가지 결점이 있는데, 결국 무한소수의 근사값 문제점을 그대로 가져간다는 점과, toFixed()의 결과는 String, 문자열로 나온다는 점이다.

근사값 문제점을 그대로 가져가기 때문에,

0.15.toFixed(1) // '0.1'
0.115.toFixed(2) // '0.12'

반올림이지만 다음과 같은 경우가 발생하고,

문자열이기 때문에

0.1.toFixed(1) + 0.2.toFixed(1)

같은 방식으로 사용하면 결과값이 0.10.2로 나와버리게 되므로

 (0.1 + 0.2).toFixed(1)

와 같은 방식으로 사용해야 하고, 결과값을 다시 계산에 사용하려면 Number()나 단항연산자+를 사용해 다시 숫자로 변형해 사용해야한다.

2. * 10^n => / 10^n


두번째 방법인 10^n을 곱해 정수 단위까지 올려준 뒤, 계산하고 10^n으로 나누어 다시 소수로 단위를 되돌리는 방법이다.

예시로 함수를 하나 만들어보았다.

const add = (a, b) => {
  let ten = Math.max(String(a).length, String(b).length) - 2
  let answer = (a * (10 ** ten)) + (b * (10 ** ten))
  
  return answer / (10 ** ten)
}

add(0.1, 0.2) // 0.3

예시에 불과하지만, 다음과 같은 방식으로 소수점 아래의 계산을 진행시킬 수 있다.

소수에서만 문제가 발생할까?


그렇다면 숫자계산에서 소수 범위에서만 문제가 발생할까?
그렇지 않다, Number 값은 기본적으로 2^53 - 1 까지만 안정적으로 표현할 수 있는데, 이에 대해서 다음 포스트에서 다뤄보려고 한다.

profile
안녕하세요, Blog 2022.06 ~

0개의 댓글