이 영역을 누르면 첫 페이지로 이동
Arc 블로그의 첫 페이지로 이동

Arc

페이지 맨 위로 올라가기

Arc

[Java] 위도/경도 값에 BigDecimal or double?

  • 2024.04.30 01:57
  • Language/Java
글 작성자: SeoArc

위/경도 값을 저장할 때 BigDecimal을 사용하는 것을 본 적이 있다.

하지만 BigDecimal을 사용하는 것이 좋은걸까? double을 사용하는 건 좋지 않은 걸까?

BigDecimal과 double에 어떤 특징이 있는지, 위경도에 어느 자료형이 적합할지 한 번 살펴보자.

 

 

double의 부동소수점 문제

오늘날 컴퓨터는 대부분 IEEE 754 부동 소수점 방식을 사용하기 때문에 Java에서 double을 사용해 소수를 표현한다면 소수점 약 15자리부터 오차가 발생할 수 있다.

 

 

오차를 해결하려면?

Java에는 BigDecimal이라는 자료형으로 부동소수점 방식으로 인해 생기는 오차를 막을 수 있다.

 

https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html

 

BigDecimal (Java Platform SE 8 )

Returns a string representation of this BigDecimal, using engineering notation if an exponent is needed. Returns a string that represents the BigDecimal as described in the toString() method, except that if exponential notation is used, the power of ten is

docs.oracle.com

 

 

BigDecimal은 어떻게 정확하게 소수를 표시할 수 있을까?

BigDecimal의 내부를 살펴보면 여러 상태 값들이 있는 것을 확인할 수 있다.

BigDecimal은 이러한 상태 값들을 활용하여 정수로 소수를 다루기 때문에 정확한 표현을 할 수 있는 것이다.

 

BigDecimal이 소수를 표현하기 위한 상태 값들은 다음과 같은 것들이 있다.

BigInteger intVal;   // 정수부 값
int precision;       // 정수부, 소수부의 길이를 합한 값
int scale;           // 소수부의 길이
String stringCache;  // 숫자를 String으로 변환한 값
long intCompact;     // 소수점을 제외한 전체 수

 

 

BigDecimal은 valueOf를 통해 생성하자

만약 BigDecimal을 사용하게 된다면 생성자를 통한 객체 생성은 피하는 것이 좋다.

 

다음 코드를 살펴보자.

double number = 1.0;
BigDeciaml bigDecimal = new BigDecimal(number); // 0.100000000000000005551115123...

위 코드의 경우 double에서 이미 오차가 발생한 상황이다. 그렇기 때문에 BigDecimal에 저장된 값도 오차가 있는 값이 들어가게 된다.

 

하지만 다음과 같이 valueOf를 통해 생성하면 해결할 수 있다.
valueOf는 내부에서 문자열로 변환시키는 로직을 수행하기 때문에 문제가 되지 않는다.

double number = 1.0;
BigDecimal bigDecimal = BigDecimal.valueOf(number);
public static BigDecimal valueOf(double val) {  
    return new BigDecimal(Double.toString(val));  
}

위 코드에서 알 수 있듯, 직접 문자열로 변환하면 생성자를 사용해서 생성해도 위 문제를 해결할 수 있다.

double number = 1.0;
BigDecimal bigDecimal = new BigDecimal(Double.toString(number));

 

 

BigDecimal의 단점

BigDecimal을 사용했을 때 단점은 무엇이 있을까

 

제일 먼저 사용하기 까다롭다는 점이 있다.

수를 생성할 때 항상 객체 생성을 해야하며, 연산을 할 때도 연산자가 아닌 메서드를 통해 수행해야 한다.

즉, 다음과 같은 로직은 수행할 수 없다.

BigDeciaml a = BigDecimal.valueOf(1.1);
BigDeciaml b = BigDecimal.valueOf(2.2);
BigDecimal result = a * b; // error

위 로직을 수행하려면 다음과 같이 변경해주어야 한다.

BigDeciaml a = BigDecimal.valueOf(1.1);
BigDeciaml b = BigDecimal.valueOf(2.2);
BigDecimal result = a.multiply(b);

 

또, db에서의 연산도 꺼려진다. BigDecimal과의 mapping을 지원해주지 않는 db가 많아 형변환을 거쳐야 하기에 double보다 다루기 힘들 것이다.

 

두번째로, 메모리 오버헤드다. BigDecimal은 위에서 말했듯이 수를 표현하기 위해 항상 객체 생성이 필요하다. 또 BigDecimal은 정밀한 숫자를 표현하기 위해 객체가 차지하는 메모리 공간이 적지 않다.

 

위 단점이 있더라도 만약 정밀함이 더 중요한 서비스라면(ex 돈과 관련된 기능) BigDecimal의 사용은 필수적일 수 있다.

 

 

위/경도에는 어떤 자료형을 쓸까

만약 개발 시 지도 api를 활용한 서비스를 준비한다면 위경도 값을 api를 통해 받을 것이다.
대부분의 지도 API(Google Map, 네이버 지도, 카카오맵 등)은 WGS84 위도/경도 좌표계를 사용한다.


그럼 api를 받을 때 다음과 같은 형식으로 받을 것이다.

{ latitude: 37.51243121154322, longitude: 127.03763421212431 }


여기서 소수점 오차를 얼마나 허용할 수 있을까?

위/경도에서 5자리까지는 약 1m, 6자리는 약 10cm, 7자리는 약 1cm의 차이가 있다.
만약 매우 정밀한 위치 표시를 요구하는게 아니라면 double을 사용해서 좌표를 표시해도 무리가 없어보인다.

 

마무리

만약 위치, 지도를 사용하는 서비스를 개발 중이라면 위/경도의 자료형을 한 번 고민을 해보는 것이 좋을 것 같다.

 

참고
https://ko.wikipedia.org/wiki/IEEE_754
https://f-lab.kr/insight/understanding-and-utilizing-bigdecimal
https://devs0n.tistory.com/102
https://programtip.tistory.com/2456
저작자표시 (새창열림)

'Language > Java' 카테고리의 다른 글

[Java] System.out.println의 사용을 지양하자  (0) 2024.06.21
[Java] utility class는 무엇으로 구현하는 것이 좋을까?  (1) 2024.04.15
[Java] 제네릭(Generic)  (0) 2024.03.12
[Java] Mockito  (0) 2023.07.31
[Java] hashCode()  (1) 2023.07.02

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [Java] System.out.println의 사용을 지양하자

    [Java] System.out.println의 사용을 지양하자

    2024.06.21
  • [Java] utility class는 무엇으로 구현하는 것이 좋을까?

    [Java] utility class는 무엇으로 구현하는 것이 좋을까?

    2024.04.15
  • [Java] 제네릭(Generic)

    [Java] 제네릭(Generic)

    2024.03.12
  • [Java] Mockito

    [Java] Mockito

    2023.07.31
다른 글 더 둘러보기

정보

Arc 블로그의 첫 페이지로 이동

Arc

  • Arc의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록

카테고리

  • 분류 전체보기 (109)
    • Language (28)
      • C++ (0)
      • C# (0)
      • Java (28)
    • Algorithm (47)
      • Algorithm (15)
      • Data Structure (6)
      • PS (26)
    • Computer Science (22)
      • Design Pattern (1)
      • Network (14)
      • OS (7)
    • Game (0)
      • Unity (0)
    • Backend (5)
      • Spring (3)
      • JPA (2)
    • DB (0)
      • SQL (0)
    • DevOps (1)
      • AWS (0)
      • Docker (2)
      • Jenkins (0)
      • Nginx (0)
    • Software Engineering (4)
      • OOP (4)
    • AI (0)
      • Machine Learning (0)
    • Others (0)

최근 글

인기 글

댓글

공지사항

아카이브

태그

  • network
  • algorithm
  • graph
  • 네트워크
  • java
  • 자바
  • 알고리즘
  • 그래프

나의 외부 링크

정보

SeoArc의 Arc

Arc

SeoArc

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. © SeoArc. Designed by Fraccino.

티스토리툴바