• BigDecimal?

    BigDecimal은 Java 언어에서 숫자를 정밀하게 저장하고 표현할 수 있는 유일한 방법

  • 사용하는 이유

    Java 에서의 실수

    • Java 에서 제공하는 실수형 데이터 타입에는 float와 double이 있다. 정수형 int, long 타입과 동일하게 각각 4, 8바이트의 메모리 공간을 사용하지만 실수를 가수와 지수 부분으로 나누어 표현하는 부동 소수점 방식을 기반으로 정수보다 더 넓은 범위의 값을 표현할 수 있다. 참고로 자바에서는 실수 연산에서 double 타입을 기본적으로 사용한다.

    부동소수점 방식의 문제

    • Java 에서 사용하는 소수점 방식으로 컴퓨터는 실수 표현을 근사값으로 표현하기 때문에 오차가 존재한다.

    • Test

      @Test
      void test() {
      	double a = 100.0000000005;
      	double b = 10.0000000004;
      	
      	assertThat(a - b).isEqualTo(90.0000000001);
      }
      

      결과

      Untitled

    위와 같은 문제가 있기 때문에 BigDecimal 객체를 사용 한다

  • 사용방법

    • 선언

         @Test
          void initBigDecimal() {
              //문자열로 초기화해야 정확한 값 사용가능.
      
              //double 타입을 그대로 초기화하면 기대값과 다른 값을 가진다.
              //0.01000000000000000020816681711721685132943093776702880859375
              BigDecimal a = new BigDecimal(0.01);
      
              //문자열로 초기화
              //0.01
              BigDecimal b = new BigDecimal("0.01");
      
              //double#toString을 이용하여 문자열로 초기화
              //0.01
              BigDecimal c = BigDecimal.valueOf(0.01);
      
          }
      

      valuOf() 메서드의 경우 기존에 생성된 값의 객체가 있으면 캐싱 해놓은 값에 바로 접근 할 수 있기 때문에 더 빠르다

    • 연산

      • 비교 연산

        @Test
            void bigDecimal() {
                BigDecimal a = new BigDecimal("0.01");
                BigDecimal b = new BigDecimal("0.010");
        
                // 객체의 레퍼런스 주소에 대한 비교 연산자로 객체의 주소가 다르므로 false (new 연산자를 사용하여 서로 다른 주소를 가짐)
                // false
                boolean result = (a == b);
        //        System.out.println(result);
        
                // 소수점 맨 끝의 0까지 완전히 값이 동일해야 true 반환
                // false
                result = a.equals(b);
        //        System.out.println(result);
                // 소수점 맨 끝의 0을 무시하고 값이 동일하면 0, 적으면 -1, 많으면 1을 반환
                // 0
                int result2 = a.compareTo(b);
        //        System.out.println(result2);
            }
        
      • 사칙 연산

        BigDecimal add(BigDecimal val) //덧셈
        BigDecimal subtract(BigDecimal val) //뺄셈
        BigDecimal multiply(BigDecimal val) //곱하기
        BigDecimal divide(BigDecimal val) //나누기
        BigDecimal remainder(BigDecimal val) //나머지
        
    • 소수점 처리

      • 종류
      // 소수점 이하를 절사한다.
      // 1
      new BigDecimal("1.1234567890").setScale(0, RoundingMode.FLOOR);
      
      // 소수점 이하를 절사하고 1을 증가시킨다.
      // 2
      new BigDecimal("1.1234567890").setScale(0, RoundingMode.CEILING);
      // 음수에서는 소수점 이하만 절사한다.
      // -1
      new BigDecimal("-1.1234567890").setScale(0, RoundingMode.CEILING);
      
      // 소수점 자리수에서 오른쪽의 0 부분을 제거한 값을 반환한다.
      // 0.9999
      new BigDecimal("0.99990").stripTrailingZeros();
      
      // 소수점 자리수를 재정의한다.
      // 원래 소수점 자리수보다 작은 자리수의 소수점을 설정하면 예외가 발생한다.
      // java.lang.ArithmeticException: Rounding necessary
      new BigDecimal("0.1234").setScale(3);
      
      // 반올림 정책을 명시하면 예외가 발생하지 않는다.
      // 0.123
      new BigDecimal("0.1234").setScale(3, RoundingMode.HALF_EVEN);
      
      // 소수점을 남기지 않고 반올림한다.
      // 0
      new BigDecimal("0.1234").setScale(0, RoundingMode.HALF_EVEN);
      // 1
      new BigDecimal("0.9876").setScale(0, RoundingMode.HALF_EVEN);
      

      <aside> 💡 • RoundingMode.HALF_EVEN은 Java의 기본 반올림 정책으로 금융권에서 사용하는 Bankers Rounding와 동일한 알고리즘이다. 금융권에서는 시스템 개발시 혼란을 막기 위해 요구사항에 반올림 정책을 명확히 명시하여 개발한다.

      </aside>