상세 컨텐츠

본문 제목

[Javascript] 0.4 + 0.3 은 0.7이 아닐 수도 있다 / 자바스트립트의 이상한 소수 계산법

프론트 연구 노트

by bydawn25 2022. 4. 5. 08:55

본문

어느날 아래와 같은 현상을 발견했다. 개발자 인생 3년만에 처음보는 현상이였다.

158.62 + 12.38 = 171.09999999991

 

 

 

 

 

내가 눈이 이상한가? 아무리 눈을 씹고 봐도 갑자기 9가 생긴 느낌이였다. 아니 뭐지? 지금까지 react, angular, javascript 심지어 node.js를 사용할때도 floating number 덧샘에서 문제가 생긴적이 없었는데.

 

저 결과를 보고 있자니 어떤 language든 덧샘은 완전하다라는 내 대전재가 깨진 느낌이였다. 😂

 

그래서 열심히 구글링을 해보았더니 아래와 같은 포스팅을 발견할 수 있었다.

 

 

 

 

https://stackoverflow.com/questions/5037839/avoiding-problems-with-javascripts-weird-decimal-calculations

 

Avoiding problems with JavaScript's weird decimal calculations

I just read on MDN that one of the quirks of JS's handling of numbers due to everything being "double-precision 64-bit format IEEE 754 values" is that when you do something like .2 + .1 you get 0.

stackoverflow.com

이런 문제가 20년 전부터 있던 문제였다니! 역시 자바스크립트 언어 계열은 놀랍도록 복잡하다

 

 

 

 

그러면 원인을 함께 알아보도록 하겠다 ^0^

 

우리는 1/3을 소수로 표현할 수 없다. 삼분의 일은 0.333333이므로 인간은 그냥 0.3333...정도로 인식한다. 컴퓨터도 마찬가지이다.

 

우리가 봤을때 1/10은 0.1으로 완전 깔끔하게 딱 떨어지는 숫자이지만 이진법으로 생각하면 (그렇다 이진법이 그 이유이다 .. !!) 나타낼 수 없는 숫자이다. 이진법으로 봤을때 1 = 2^0 이므로 0.1을 표현할 수 있는 방법이 없는 경우도 있고 우리가 알고있는 방법과 다른 경우도 있다.

 

0.1 = 0.0001100110011001101

위 결과는 구글에서 binary converter를 이용한 결과이다.

 

 

 

 

웹은 표준적인 환경이다. 네트워크도 마찬가지. 웹과 네트워크를 개발할때 몰라도 상관없지만 알면 참 좋은게 표준이다.

 

Javascript는 Floating number(소수)의 계산을 위해 [ IEEE 754-1985 ] 표준을 사용하는데 가장 최근 수정된 날짜는 2019년이다. 처음으로 표준화 되었을때는 1985년이라고 하니 .. 컴퓨터의 역사만큼 오래된듯하다.

 

컴퓨터의 역사하니까 제주도 넥슨 박물관을 다시한번 가보고 싶다(뜬금)

 

위키피디아를 참고하니 아래와 같은 정확도를 가진다.

 

Single precision 32 bits Approximately 7 decimal digits
Double precision 64 bits Approximately 16 decimal digits

내가 봤던 에러가 0.99999998 느낌이었으니 아마 Single precision에 의해 계산이 되었던 듯 싶다.

 

 

 

 

 

확실하지 않으니 혹시 알려주실 분이 계시다면 언제나 환영이다. 댓글은 새벽이를 춤추게 한다.

 

 

 

 

 

 

자바스크립트는 확실히 여러 라이브러리를 끌어다 쓰고 있어서 그런가 다양한 타입이 존재한다.

  • 8-bit integer (signed and unsigned)
  • 16-bit integer (signed and unsigned)
  • 32-bit integer (signed and unsigned)
  • 64-bit integer (signed and unsigned)
  • 32-bit floating point64-bit floating point
  • BigInt (빅인트는 무엇인가)

내가 찾아본것만 해도 위와 같이 존재하는데 이 타입들에 따라서 precision(정확도)가 달라지고 덧샘, 뺄샘과 같은 결과도 일정하게 보장되지 않는다.

 

그러므로 데이터가 중요한 작업을 할때는 저 타입들을 신경써서 설정하던가, 데이터베이스 단에서 합의된 데이터를 불러오는 방향으로 구현해야 한다.

 

 

 

 

 

뭐 장황하게 썼지만 결론은 간단하다.

 

자바스크립트의 숫자체계는 복잡하므로 데이터가 중요한 작업을 할때는 조심하자 👍

 

 

 

 

 

관련글 더보기