레코드에 double, float과 같은 실수 타입이 있습니다. 예를 들자면, 0.1달러, 0.2달러와 같은 것들입니다. 이것을 double로 저장했을 때와 decimal로 저장했을 때 어떤 차이가 있을까요? 간단하게 알아보겠습니다.

 


 NewTable은 deci, dou, deci2, dou2 필드가 있습니다. deci가 prefix인 것은 decimal(10,5)로, dou가 prefix인 것은 double로 저장하였습니다.

 

 

 데이터들을 넣어 보겠습니다.

 

 

 이 테이블에 있는 데이터들을 보겠습니다.

 

 

 그러면 1.3, 1.3, 1.3, 1.3과 1.1, 1.1, 1.1, 1.1이 나옵니다. 여기서 deci+deci2와 dou+dou2를 출력해 보도록 하겠습니다.

 

 

 

 위와 같이 나오는데요. 각각 2.6, 2.6과 2.2, 2.2가 나옵니다. 정확한 값이 나옵니다. 그런데, 정말 정확히 나왔을 수도 있지만, 오차가 매우 작아서 정확하게 보였을 수도 있습니다. 전자인지 후자인지는, 연산 수를 늘려보면 알 듯 합니다. 만약에 오차가 조금이라도 있다면, 누적을 매우 많이 시키면 눈에 보일 만큼 불어날 것이기 때문입니다.

 


 NewTable을 바꿔봅시다. deci랑 dou 필드만 남겨두겠습니다.

 

 그리고 deci가 0.1, dou가 0.1인 레코드를 11만개 insert를 합니다.

 

 

 그렇게 하면, count 함수를 썼을 때, 결과값이 11만이 나올 겁니다.

 

 

 11만이 나오는군요. 그리고 전체 레코드를 조회해 보겠습니다.

 

 

 그러면 0.1, 0.1만 잔뜩 있는 것을 볼 수 있습니다. deci의 sum과 dou의 sum을 구해 보겠습니다.

 

 

 쿼리는 이렇게 작성하면 되겠군요.

 

 

 결과값을 보니, 차이가 있음을 알 수 있습니다. sum(deci)는 11000이 나온 반면에, sum(dou)는 11000.0000000255가 나왔음을 알 수 있습니다. 이것은 0.1이 double이나 float와 같은 부동 소수점으로 표현되지 못하기 때문에 오차가 생기고, 이 오차가 11만번이나 누적되었기 때문입니다.

 

 따라서, 정확한 값을 저장해야 할 때에는 double이나 float를 쓰면 안 됩니다. decimal을 고려해 보아야 합니다. 하지만, 이것도 공식 문서에서 보면 제한이 있으니, 상황에 맞게 잘 쓰는 게 좋습니다.

 


 그러면, Application에서 BigDecimal로 저장된 것은 어떻게 불러오면 좋을까요? jdbc를 이용한다면, ResultSet 문서에, 우리가 원하는 것을 얻어오는 getBigDecimal이 나와 있습니다. 이 메서드를 이용하시면 됩니다. 

 

 

 이것은 정확하게 0.1을 11만번 더하면 11000이라는 값을 떨굴까요? 테스트 프로그램을 돌려보면 쉽게 알 수 있습니다.

 

 

 위 프로그램은 0.1을 11만번 더하는 것인데, 하나는 BigDecimal, 다른 하나는 double입니다. 결과는 어떨까요?

 

 

 놀랍게도, BigDecimal은 정확하게 나오지만, double은 정확하게 나오지 않습니다. double을 11만번 더한 것은, 오차가 누적되면서, 결과값에 차이가 날 만큼 오차가 생겨버렸습니다. 필드가 실수값인데, 정확한 값이 중요하다. 싶으면 double 말고 고정 소수점을 표현하는 Decimal이나 문자열화 시켜서 저정하는 varchar를 고려해 보는 게 좋겠습니다.

 

 varchar로 저장한다면 Application에서 처리할 때, String으로 받고, BigDecimal로 처리하시면 됩니다.

댓글을 달아 주세요