일전에 백준에서 큰수에 대한 문제를 풀었을때 만났었던 클래스인데 이번에 또 만나게 되어 BigDecimal과 BigInteger에 대한 설명을 포스팅하려고 합니다.
BigInteger를 사용한 백준 문제 (10757번 큰 수 A+B)
https://www.acmicpc.net/problem/10757
MySQL에서 Data에 대한 매핑을 보다가 BIGINT 즉 큰수에 대한 값을 자바에서 convert해서 가져오는 과정에서 사용되는 클래스로 java.math.BigDecimal이 사용되는 것을 확인 할 수 있습니다.
그럼 BigDecimal과 BigInteger가 무엇인지에 대해서 알아보겠습니다.
BigDecimal 클래스
실수형 자료형으로 사용되는 float과 double등은 정밀도에 한계가 있어 원하는 값이 나오지 않을 수 있습니다.
왜냐하면 내부적으로 수를 저장할 때 이진수의 근사치를 저장하기 때문입니다. 저장된 근사치 값을 다시 십진수로 변환하면서 오차가 발생합니다.
반면에 BigDecimal 타입은 내부적으로 수를 십진수로 저장하여 아주 작은 수과 큰 수의 연산에 대해 거의 무한한 정밀도를 보장합니다.
그래서 속도가 느리고 사용하기 불편하지만, 숫자의 오차를 허용하지 않는 정확한 자료형이기 때문에 소수점 아래의 값조차 정확하게 계산해야 할 때 경우 해당 자료형을 사용하게 됩니다.
생성방법
// 문자열로 생성
BigDecimal bigDecimal = new BigDecimal("123.456");
//double 타입으로 생성-오차발생 가능성
BigDecimal bigDecimal = new BigDecimal(123.456);
//int, long 타입으로 생성
BigDecimal bigDecimal = new BigDecimal(123456);
//valueOf 생성
BigDecimal bigDecimal = BigDecimal.valueOf(123456);
BigDecimal은 기본적으로 생성자의 인자값에 문자열값을 넣어 생성이 가능한데,
double, int, long타입으로도 생성이 가능하다. double의 정밀도의 한계가 있어 사용하는 클래스 이므로 double타입으로 생성할 경우 오차 발생 가능성이 존재한다.
사칙연산
BigDecimal num1 = new BigDecimal("123.456");
BigDecimal num2 = new BigDecimal("789.123");
System.out.println("BigDecimal 덧셈 :" + num1.add(num2));
System.out.println("BigDecimal 뺄셈 :" + num1.subtract(num2));
System.out.println("BigDecimal 곱셈 :" + num1.multiply(num2));
// 나눗셈의 경우 무한대로 나눠질 수 있기에 자리 수를 정해준다.
// 아래의 경우는 소수점 아래 3자리까지만 출력했다.
// RoundingMode.HALF_EVEN은 Java의 기본 반올림 정책으로 금융권에서 사용하는 Bankers Rounding와 동일한 알고리즘
System.out.println("나눗셈 :" + num1.divide(num2, 3, RoundingMode.HALF_EVEN));
System.out.println("나머지 :" + num1.remainder(num2));
BigDecimal 덧셈 :912.579
BigDecimal 뺄셈 :-665.667
BigDecimal 곱셈 :97421.969088
BigDecimal 나눗셈 :0.156
BigDecimal 나머지 :123.456
BigDecimal은 기본적으로 +,-,*,/과 같은 사칙연산을 그대로 사용할 수 없어서 .add() .substract() .multiply() .divide()와 같이 메소드를 사용하여 사칙 연산을 할 수 있다.
나눗셈을 사용할때에는 소수점의 표시를 하는 것을 주의하자
BigDecimal 값 비교
거의 이 포스팅을 하는 이유라고 보면 될 것 같다.
BigDecimal은 >,<와 같이 일반적으로 값을 비교한는 것이 불가능하다.
그래서 메소드를 통해서 값 비교를 하여 누가 더 큰지 작은지를 판별 할 수 있다.
BigDecimal num1 = new BigDecimal("123.567");
BigDecimal num2 = new BigDecimal("456.789");
// 같으면 0 반환, 적으면 -1, 많으면 1 반환
int result = num1.compareTo(num2);
System.out.println("결과 : " + result);
결과 : -1
compareTo() 메소드를 사용하여 값의 대소를 비교한다.
값을 넣는 기준으로
앞의 숫자가 크면 1, 같으면 0, 뒤의 숫자가 크면 -1 이렇게 생각해서 외우면 편할 것 같다.
BigDecimal 에서 다른 자료형으로 형 변환
BigDecimal num = new BigDecimal("123.456");
String String_num = num.toString(); // String형으로 변환
int int_num = num.intValue(); // int형으로 변환
float float_num = num.floatValue(); // float형으로 변환
double double_num = num.doubleValue(); // double형으로 변환
long long_num = num.longValue(); // long형으로 변환
각각
BigDecimal을 String로 형변환
BigDecimal을 int로 형변환
BigDecimal을 float로 형변환
BigDecimal을 double로 형변환
BigDecimal을 long로 형변환
하는 방법이다.
BigIntger 클래스
long형으로도 표현이 안되는 엄청나게 큰 범위의 정수를 표현할때 사용하는 클래스이다. BigDecimal과 마찬가지로
(+,-,*,/,%)을 기호로 사칙연산을 할 수 없고, BigInteger에서 제공하는 메서드를 이용해야 한다.
참고로 BigIntger의 범위는 무한대이므로 단순히 long을 벗어나는 범위를 넘어 엄청나게 큰 수의 표현에서 사용한다고 보면 될 것 같습니다.
생성방법
// 문자열로 생성
BigInteger bigInteger = new BigInteger("123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789");
//n진수 문자열로 생성
BigInteger bigInteger = new BigInteger("FFFF", 20);
//valueOf 생성
BigInteger bigInteger = BigInteger.valueOf(123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789);
long형의 범위는 -9223372036854775808~9223372036854775807까지를 표현을 할 수 있다.
대충 19자리 정도까지는 long형으로 표현이 가능하나 그것을 넘는 숫자부터는 long형으로 표현이 불가능해서 BigInteger클래스를 사용해야 한다.
사칙연산
BigInteger bigNum = new BigInteger("3");
// 덧셈
System.out.println("3+3="+bigNum.add(BigInteger.valueOf(3)));
// 뺄셈
System.out.println("3-3="+bigNum.subtract(BigInteger.valueOf(3)));
// 곱셈
System.out.println("3*3="+bigNum.multiply(BigInteger.valueOf(3)));
// 나눗셈
System.out.println("3/3="+bigNum.divide(BigInteger.valueOf(3)));
// 나머지
System.out.println("3%3="+bigNum.mod(BigInteger.valueOf(3)));
3+3=6
3-3=0
3*3=9
3/3=1
3%3=0
BigIntger값 비교
BigDecimal과 마찬가지로 compareTo()를 사용하여 비교할 수 있다. 같으면 0, 앞 숫자가 더 크면 1, 뒷 숫자가 더 크면 -1을 반환한다.
System.out.println(BigInteger.valueOf(3).compareTo(BigInteger.valueOf(3)));//0
System.out.println(BigInteger.valueOf(3).compareTo(BigInteger.ONE));//1
System.out.println(BigInteger.ONE.compareTo(BigInteger.valueOf(3)));//-1
참고로 0,1,2,10은 BigInteger.ZERO, BigInteger.ONE, BigInteger.TWO, BigInteger.TEN으로 클래스에서 제공한다.
BigIntger 에서 다른 자료형으로 형 변환
BigInteger bigNumber = BigInteger.valueOf(12345);
System.out.println(bigNumber.intValue()); // int형으로 변환
System.out.println(bigNumber.longValue()); // long형으로 변환
System.out.println(bigNumber.floatValue()); // float형으로 변환
System.out.println(bigNumber.doubleValue()); // double형으로 변환
System.out.println(bigNumber.toString()); // String형으로 변환
각각
BigInteger을 int로 형변환
BigInteger을 long로 형변환
BigInteger을 float로 형변환
BigInteger을 double로 형변환
BigInteger을 String로 형변환
하는 방법이다.
String을 BigIntger로 변환
String convertStringValue = "2022";
BigInteger convertBigIntgerValue = new BigInteger(convertStringValue);
그렇다면 위의 백준의 문제인
해당 문제도
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.StringTokenizer;
class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine() + " ");
BigInteger A = new BigInteger(st.nextToken());
BigInteger B = new BigInteger(st.nextToken());
System.out.println(A.add(B));
}
}
위와 같이 사용할 수 있다.
참고
https://ajdahrdl.tistory.com/14
https://technote-mezza.tistory.com/104
'JAVA' 카테고리의 다른 글
[자바 Java] Java.sql.Time을 milliseond로 변환 (0) | 2022.03.11 |
---|---|
[자바 JAVA] 예외의 종류 (0) | 2022.02.17 |
[JAVA 자바] 메소드 체이닝이란? (1) | 2022.01.11 |