본문 바로가기
Algorithm

Java BigDecimal

by 신지형 2021. 6. 1.

Java BigDecimal 클래스는 임의 정밀도의 부호있는 십집수를 처리할 수 있습니다.

실수형 문자열 요소가 들어있는 배열 s가 주어지면, 내림차순으로 정렬하고 출력합니다

 

  1.  출력할 되는 요소는, 주어진 실수형 문자열과 다르지 않아야 합니다
  2.  수의 의미로 같은 실수일 경우, 정렬순서가 원본 배열과 같아야합니다.
    ex ) ".1" == "0.1"

 

제약조건

  •  i <= { s의 크기 } <= 200
  • s[i] 요소는 최대 300 자릿수

입력예시 (sample input)

String[] s = {
    "-100",
    "50",
    "0",
    "56.6",
    "90",
    "0.12",
    ".12",
    "02.34",
    "000.000"
};

 

출력예시 (sample output)

90
56.6
50
02.34
0.12
.12
0
000.000
-100

 

 

 

문제

String[] s = {
    "-100",
    "50",
    "0",
    "56.6",
    "90",
    "0.12",
    ".12",
    "02.34",
    "000.000"
};

// 이 부분의 코드를 작성

for (String str : s) {
    System.out.println(st);
}

 

해설

  • 출력은 문자열 형태, 정렬은 실수의 크기로 비교한다.
  • 출력하는 코드가 이미 작성되어 있고, 배열 s를 참조하고 있다.
  • 출제자가 의도하는 것은, 문자열 배열 s를 변경하는것이라고 볼 수 있다.
  • 제약 조건을 살펴보면 배열 s의 실수형태의 요소는 최대 300 자릿수가 들어갈 수 있습니다.
    때문에 우리는 BigDecimal이 필요합니다.

 

배열을 정렬하는 간단한 방법으로는 Arrays.sort() 기본 API를 사용하는 것입니다.

배열의 타입이 문자열이므로, 기본 유니코드 순서로 정렬될 것입니다.

 

따라서 우리는 정렬 순서 기준을 변경할 방법이 필요합니다.

java.util.Comparator<T> 인터페이스의 compare 메소드를 구현

 

String[] s = {
    "-100",
    "50",
    "0",
    "56.6",
    "90",
    "0.12",
    ".12",
    "02.34",
    "000.000"
};

// 이 부분의 코드를 작성

Arrays.sort(s, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return new BigDecimal(o2).compareTo(new BigDecimal(o1));
    }
});

for (String str : s) {
    System.out.println(st);
}

Comparator의 compare 메소드는 정렬기준으로 이 인터페이스를 구현한 객체를 기준으로 정렬할 때는

compare 메소드의 반환 값을 기준으로 정렬됩니다.

 

compare 메소드의 반환 값은 다음과 같습니다.

음수 : o1 < o2

0     : o1 == o2

양수 : o1 > o2

 

이것을 숫자적 의미로 풀어헤쳐 표현하면 다음과 같습니다.

int a = 100
int b = 200
int compare(int a, int b) {
    return a - b;
}

위 코드의 연산결과는 -100으로 음수 입니다.

결과가 음수라면 a항은 반드시 b항보다 작다는 것을 알 수 있습니다.

결과가 0 이라면 a항은 반드시 b항과    같다는 것을 알 수 있습니다.

결과가 양수라면 a항은 반드시 b항보다 크다는 것을 알 수 있습니다.

 

결론적으로 말씀드리면 Arrays.sort는 compare의 반환 값이 음수거나 0이면 정렬위치를 변경하지 않습니다.

기본 오름차순이기 때문에 결과가 음수면 변경할 이유가 없습니다.

결과가 0이면? 같은 수치이기때문에 굳이 변경할 이유가 없습니다.

 

우리는 내림차순 으로 출력을 수행해야하기 떄문에 한번 더 생각을 해봅시다.

 

int a = 100
int b = 200
int compare(int a, int b) {
    return b - a;
}

위와 같이 a항과 b항의 위치를 바꾸면 어떻게 될까요 ?

결과는 200 - 100  = 100 으로 양수로 a가 b보다 작음에도 위치 변경이 수행될 것입니다.

즉 b가 앞의 요소로 변경이 되겠죠

 

때문에 compare 메소드의 2번째 매개변수를 a항으로 연산을 수행하면, 내림차순 정렬(역정렬)을 수행할 수 있습니다.

 

 

Arrays.sort(s, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return new BigDecimal(o2).compareTo(new BigDecimal(o1));
    }
});
  1. 우리는 문자열 형태로 출력을 하되, 최대 300자릿수를 허용하는 실수 크기비교를 해야하기 때문에
    BigDecimal 인스턴스를 생성합니다.
  2. BigDecimal 클래스는 정렬을 위해 안전한 크기 비교를 수행 후, 음수, 0, 양수 값을 반환하는
    compareTo 메소드를 구현해두었기 때문에 이 메소드를 사용하여 크기 비교를 수행합니다.
  3. 내림차순 정렬을 수행을 위해서 2번째 매개변수를 기준으로 비교를 수행합니다.

 

 

이런 문자열 형태 숫자를 숫자타입으로 변경할 때 다음과 같은 유효성 체크와 그에 따른 후처리가 필요합니다.

Arrays.sort(s, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        if (o1 == null ||  o1.trim().length() == 0 ||
            o2 == null ||  o2.trim().length() == 0)
            return 0;
            
        // String o1, o2 isDecimal?
    
        return new BigDecimal(o2).compareTo(new BigDecimal(o1));
    }
});

매개변수가 null이거나 공백문자열일 때 BigDecimal 인스턴스를 생성하지 못하고 예외를 발생시킬 것입니다.

 

또한 null 이거나 공백문자열이 아니더라도 숫자로 변경 불가능한 문자열일 수도 있습니다.

예를들어 "abc"

 

따라서 저 코드에는 null, 공백, 숫자로 변환가능한 문자열인가? 를 확인하는 작업이 필요합니다.

그리고 이런 데이터가 매개변수로 전달되었을 때, 후 처리도 고민해봐야합니다.

 

 

마지막으로... 반복적으로 사용되는 코드라면, 매번 Comparator 인스턴스를 생성하지말고

상수 처리하는것도 생각해볼 수 있습니다.

class Solution {
    private static final Comparator<String> BIGDECIMAL_DESC = new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return new BigDecimal(o2).compareTo(new BigDecimal(o1));
        }
    };
    public static void main(String[] args) {
        String[] s = {
            "-100",
            "50",
            "0",
            "56.6",
            "90",
            "0.12",
            ".12",
            "02.34",
            "000.000"
        };

        Arrays.sort(s, BIGDECIMAL_DESC);

        for (String str : s) {
            System.out.println(st);
        }
    }
 }

댓글