기본 콘텐츠로 건너뛰기

Java BigDecimal 완전 정리: 금액·소수 계산을 위한 메서드 사용 가이드

Java BigDecimal 메서드 완전 정리: add, multiply, divide, compareTo 사용법

BigDecimal은 Java에서 금액, 정밀한 소수 계산을 처리할 때 반드시 써야 하는 핵심 클래스입니다. 하지만 메서드가 너무 많아서 어떤 메서드를 언제 써야 하는지 헷갈리기 쉽죠.

이 글에서는 공식 문서의 Method Summary를 기준으로, 자주 쓰는 BigDecimal 메서드를 카테고리별로 정리하고 실제 실무에서 어떻게 활용하는지 예제와 함께 설명합니다.


1. BigDecimal이 필요한 이유 및 기본 개념

double, float은 이진 부동소수점이기 때문에 금액·정밀 계산에 오차가 발생합니다. 예를 들어, 세금·수수료·환율 계산처럼 소수점 자릿수와 반올림이 중요한 곳에서는 반드시 BigDecimal을 사용해야 합니다.

  • 정밀도(precision) : 전체 유효 자릿수
  • 스케일(scale) : 소수점 이하 자릿수 (예: 123.45 → scale = 2)

아래에서 나오는 많은 메서드 설명에 scale(), precision()이 등장하므로 개념을 알고 있으면 이해가 훨씬 쉽습니다.


2. 핵심 연산 메서드: add, subtract, multiply, divide

가장 많이 쓰는 연산 메서드는 다음과 같습니다. (빨간색으로 표시된 것이 특히 중요)

2-1. 더하기 – add()

  • BigDecimal add(BigDecimal augend)
    (this + augend), scale은 max(this.scale(), augend.scale())
  • BigDecimal add(BigDecimal augend, MathContext mc)
    ⇒ 더하기 결과에 MathContext 기준으로 반올림·정밀도 적용

2-2. 빼기 – subtract()

  • BigDecimal subtract(BigDecimal subtrahend)
    (this - subtrahend), scale은 두 값 중 더 큰 scale 사용
  • BigDecimal subtract(BigDecimal subtrahend, MathContext mc)
    ⇒ 반올림·정밀도 제어 포함

2-3. 곱하기 – multiply()

  • BigDecimal multiply(BigDecimal multiplicand)
    (this × multiplicand), scale = this.scale() + multiplicand.scale()
  • BigDecimal multiply(BigDecimal multiplicand, MathContext mc)
    ⇒ 곱셈 결과에 MathContext 기반 반올림 적용

2-4. 나누기 – divide()

BigDecimal에서 가장 많이 터지는 예외가 바로 divide()입니다. (무한 소수인 경우 ArithmeticException) 메서드 오버로드를 제대로 이해하는 것이 중요합니다.

  • BigDecimal divide(BigDecimal divisor)
    (this / divisor), preferred scale = this.scale() - divisor.scale()
    정확한 몫을 표현할 수 없으면 ArithmeticException 발생
  • BigDecimal divide(BigDecimal divisor, int roundingMode)
  • BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode)
    ⇒ 나눗셈 결과가 무한 소수인 경우, 지정한 반올림 모드로 처리
  • BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
  • BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
    ⇒ 결과의 소수 자릿수(scale)를 직접 지정 + 반올림 모드 결정
  • BigDecimal divide(BigDecimal divisor, MathContext mc)
    ⇒ 전체 정밀도·반올림을 MathContext로 제어

2-5. 간단 예제


// 금액 계산 예시
BigDecimal price  = new BigDecimal("1000.00");
BigDecimal qty    = new BigDecimal("3");
BigDecimal amount = price.multiply(qty);          // 3000.00

// 10% 할인
BigDecimal discountRate = new BigDecimal("0.10");
BigDecimal discount     = amount.multiply(discountRate);   // 300.0000
BigDecimal pay          = amount.subtract(discount);       // 2700.0000

// 소수 둘째 자리까지 반올림
pay = pay.setScale(2, RoundingMode.HALF_UP); // 2700.00
    

3. 비교·부호 관련 메서드: compareTo, equals, signum, abs, negate, plus

3-1. 비교 – compareTo() vs equals()

  • int compareTo(BigDecimal val)
    ⇒ this < val → 음수, this == val → 0, this > val → 양수
    값만 비교하며, scale이 달라도 값이 같으면 0 (예: 1.0 과 1.00 은 동일)
  • boolean equals(Object x)
    값 + scale까지 모두 비교 (1.0 ≠ 1.00)

3-2. 절대값·부호 – abs(), signum(), negate(), plus()

  • BigDecimal abs(), BigDecimal abs(MathContext mc) – 절대값
  • int signum() – 음수(-1), 0, 양수(1) 반환
  • BigDecimal negate(), negate(MathContext mc) – 부호 반전(-this)
  • BigDecimal plus(), plus(MathContext mc)
    (+this), 특별한 연산은 없지만 MathContext를 적용하고 싶을 때 사용

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1.00");

System.out.println(a.equals(b));      // false
System.out.println(a.compareTo(b));   // 0

BigDecimal negative = new BigDecimal("-123.45");
System.out.println(negative.abs());   // 123.45
System.out.println(negative.signum()); // -1
    

4. 나눗셈·나머지 메서드: divideToIntegralValue, divideAndRemainder, remainder

4-1. 정수부만 – divideToIntegralValue()

  • BigDecimal divideToIntegralValue(BigDecimal divisor)
  • BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc)

(this / divisor)의 정수 부분만 반환합니다. (소수점 이하 버림)

4-2. 몫과 나머지를 동시에 – divideAndRemainder()

  • BigDecimal[] divideAndRemainder(BigDecimal divisor)
  • BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc)

[0] = 몫, [1] = 나머지 를 담은 BigDecimal[]을 반환합니다.

4-3. 나머지만 – remainder()

  • BigDecimal remainder(BigDecimal divisor)
  • BigDecimal remainder(BigDecimal divisor, MathContext mc)

(this % divisor)를 BigDecimal로 반환합니다.


BigDecimal ten   = new BigDecimal("10");
BigDecimal three = new BigDecimal("3");

BigDecimal[] qr = ten.divideAndRemainder(three);
System.out.println("몫: " + qr[0]);       // 3
System.out.println("나머지: " + qr[1]);   // 1
    

5. 스케일·정밀도 관련 메서드: scale, precision, setScale, stripTrailingZeros

5-1. scale(), precision()

  • int scale() – 소수점 이하 자릿수
  • int precision() – 전체 유효 자릿수

5-2. 소수 자릿수 조정 – setScale()

  • BigDecimal setScale(int newScale)
  • BigDecimal setScale(int newScale, int roundingMode)
  • BigDecimal setScale(int newScale, RoundingMode roundingMode)

⇒ 지정한 newScale로 스케일을 맞추면서, 필요할 경우 반올림을 수행합니다.
예: 금액을 항상 소수 둘째 자리까지 맞추고 싶을 때 자주 사용.

5-3. 소수점 이동 – movePointLeft()/movePointRight(), scaleByPowerOfTen()

  • BigDecimal movePointLeft(int n) – 소수점 왼쪽으로 n자리 이동
  • BigDecimal movePointRight(int n) – 소수점 오른쪽으로 n자리 이동
  • BigDecimal scaleByPowerOfTen(int n)this * 10^n

5-4. 불필요한 0 제거 – stripTrailingZeros()

  • BigDecimal stripTrailingZeros()
    ⇒ 값은 그대로 두고, 표현상의 뒤쪽 0을 제거합니다. (예: 1.2300 → 1.23)

BigDecimal val = new BigDecimal("123.4500");
System.out.println(val.scale());             // 4
System.out.println(val.stripTrailingZeros()); // 123.45
    

6. 기본 타입·문자열 변환 메서드: valueOf, intValue, toPlainString 등

6-1. 기본 타입 변환

  • int intValue(), long longValue(), float floatValue(), double doubleValue()
  • int intValueExact(), long longValueExact(), short shortValueExact(), byte byteValueExact()
    소수점 이하가 0이 아닌 경우 예외를 던져서, 정보 손실 여부를 체크합니다.

6-2. BigInteger 변환

  • BigInteger toBigInteger()
  • BigInteger toBigIntegerExact()
  • BigInteger unscaledValue() – 스케일을 적용하기 전의 정수 값

6-3. 문자열 표현

  • String toString() – 필요시 과학적 표기(지수) 사용
  • String toPlainString() – 지수 없이 평범한 소수 형태
  • String toEngineeringString() – 엔지니어링 표기법 사용

6-4. valueOf() 팩토리 메서드

  • static BigDecimal valueOf(long val)
  • static BigDecimal valueOf(double val)
  • static BigDecimal valueOf(long unscaledVal, int scale)

주의: new BigDecimal(double) 생성자는 이진 부동소수점 특성 때문에 예상치 못한 값이 나올 수 있습니다. 금액처럼 정확한 값이 중요할 때는 항상 new BigDecimal("1000.00") 또는 BigDecimal.valueOf(1000L) 패턴을 권장합니다.


7. 실무에서 자주 쓰는 BigDecimal 패턴 예제

7-1. 안전한 생성 패턴


// 좋지 않은 예 (double 직접 사용)
BigDecimal bad  = new BigDecimal(0.1);

// 좋은 예 (문자열 또는 valueOf 사용)
BigDecimal good1 = new BigDecimal("0.1");
BigDecimal good2 = BigDecimal.valueOf(0.1); // 내부적으로 문자열 기반 처리
    

7-2. 금액 + 부가세 계산


BigDecimal supply   = new BigDecimal("100000");       // 공급가
BigDecimal vatRate  = new BigDecimal("0.1");          // 10%
BigDecimal vat      = supply.multiply(vatRate);       // 10000.0
BigDecimal total    = supply.add(vat);                // 110000.0

// 항상 두 자리로 반올림
vat   = vat.setScale(0, RoundingMode.HALF_UP);
total = total.setScale(0, RoundingMode.HALF_UP);
    

7-3. 정렬·비교시 compareTo() 사용


BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1.00");

// 정렬/크기 비교에는 compareTo() 사용
if (a.compareTo(b) == 0) {
    System.out.println("값은 같다.");
}
    

이 글에서는 Java BigDecimal의 주요 메서드를 카테고리별로 정리하고, 실무에서 자주 문제되는 나눗셈 예외, 반올림, 값·스케일 비교 차이까지 짚어봤습니다.

금액·정밀 계산이 들어가는 서비스라면, BigDecimal 메서드 특성을 이해하는 것만으로도 버그와 회계 오류를 크게 줄일 수 있습니다. 필요한 메서드는 즐겨찾기 해두고, 팀 코딩 컨벤션에도 BigDecimal 사용 규칙을 명시해 두면 좋습니다.

댓글

이 블로그의 인기 게시물

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 (Request Parameter 전체보기)

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 Java Servlet Request Parameter 완전 정복 웹 애플리케이션에서 클라이언트로부터 전달되는 Request Parameter 를 확인하는 것은 필수입니다. 이 글에서는 Java Servlet 과 JSP 에서 GET/POST 요청 파라미터를 전체 출력하고 디버깅하는 방법을 다양한 예제와 함께 소개합니다. 1. 기본 예제: getParameterNames() 사용 Enumeration<String> params = request.getParameterNames(); System.out.println("----------------------------"); while (params.hasMoreElements()){ String name = params.nextElement(); System.out.println(name + " : " + request.getParameter(name)); } System.out.println("----------------------------"); 위 코드는 요청에 포함된 모든 파라미터 이름과 값을 출력하는 기본 방법입니다. 2. HTML Form과 연동 예제 <form action="CheckParamsServlet" method="post"> 이름: <input type="text" name="username"><br> 이메일: <input type="email" name="email"><b...

PostgreSQL 달력(일별,월별)

SQL 팁: GENERATE_SERIES로 일별, 월별 날짜 목록 만들기 SQL 팁: GENERATE_SERIES 로 일별, 월별 날짜 목록 만들기 데이터베이스에서 통계 리포트를 작성하거나 비어있는 날짜 데이터를 채워야 할 때, 특정 기간의 날짜 목록이 필요할 수 있습니다. PostgreSQL과 같은 데이터베이스에서는 GENERATE_SERIES 함수를 사용하여 이 작업을 매우 간단하게 처리할 수 있습니다. 1. 🗓️ 일별 날짜 목록 생성하기 2020년 1월 1일부터 12월 31일까지의 모든 날짜를 '1 day' 간격으로 생성하는 쿼리입니다. WITH date_series AS ( SELECT DATE(GENERATE_SERIES( TO_DATE('2020-01-01', 'YYYY-MM-DD'), TO_DATE('2020-12-31', 'YYYY-MM-DD'), '1 day' )) AS DATE ) SELECT DATE FROM date_series 이 쿼리는 WITH 절(CTE)을 사용하여 date_series 라는 임시 테이블을 만들고, GENERATE_SERIES 함수로 날짜를 채웁니다. 결과 (일별 출력) 2. 📅 월별 날짜 목록 생성하기 동일한 원리로, 간격을 '1 MONTH' 로 변경하면 월별 목록을 생성할 수 있습니다. TO...

CSS로 레이어 팝업 화면 가운데 정렬하는 방법 (top·left·transform 완전 정리)

레이어 팝업 센터 정렬, 이 코드만 알면 끝 (CSS 예제 포함) 이벤트 배너나 공지사항을 띄울 때 레이어 팝업(center 정렬) 을 깔끔하게 잡는 게 생각보다 어렵습니다. 화면 크기가 변해도 가운데에 고정되고, 모바일에서도 자연스럽게 보이게 하려면 position , top , left , transform 을 정확하게 이해해야 합니다. 이 글에서는 아래 내용을 예제로 정리합니다. 레이어 팝업(center 정렬)의 기본 개념 자주 사용하는 position: absolute / fixed 정렬 방식 질문에서 주신 스타일 top: 3.25%; left: 50%; transform: translateX(-50%) 의 의미 실무에서 바로 쓰는 반응형 레이어 팝업 HTML/CSS 예제 1. 레이어 팝업(center 정렬)이란? 레이어 팝업(레이어 팝업창) 은 새 창을 띄우는 것이 아니라, 현재 페이지 위에 div 레이어를 띄워서 공지사항, 광고, 이벤트 등을 보여주는 방식을 말합니다. 검색엔진(SEO) 입장에서도 같은 페이지 안에 HTML이 존재 하기 때문에 팝업 안의 텍스트도 정상적으로 인덱싱될 수 있습니다. 즉, “레이어 팝업 센터 정렬”, “레이어 팝업 만드는 방법”과 같이 관련 키워드를 적절히 넣어주면 검색 노출에 도움이 됩니다. 2. 질문에서 주신 레이어 팝업 스타일 분석 질문에서 주신 스타일은 다음과 같습니다. <div class="layer-popup" style="width:1210px; z-index:9001; position:absolute; top:3.25%; left:50%; transform:translateX(-50%);"> 레이어 팝업 내용 <...