자바의 수 연산은 기본 자료형이나 BigDecimal 등의 클래스를 이용한다.
보통, Double(Wrapper class)와 BigDecimal 중 어떤 것을 사용해야 하는지로 고민하게 된다.
기본적인 수 연산은 +, -, *, /, % 연산자를 기본 자료형에 사용하면 될 것인데,
왜 BigDecimal 등의 숫자 클래스를 사용하여 연산을 수행할까?
이와 같은 질문을 스택오버플로우에서 발견하고 답변을 찾았다.
A BigDecimal is an exact way of representing numbers. A Double has a certain precision. Working with doubles of various magnitudes (say d1=1000.0 and d2=0.001) could result in the 0.001 being dropped alltogether when summing as the difference in magnitude is so large. With BigDecimal this would not happen.
The disadvantage of BigDecimal is that it's slower, and it's a bit more difficult to program algorithms that way (due to + - * and / not being overloaded).
If you are dealing with money, or precision is a must, use BigDecimal. Otherwise Doubles tend to be good enough.
I do recommend reading the javadoc of BigDecimal as they do explain things better than I do here :)
출처: https://stackoverflow.com/questions/3413448/double-vs-bigdecimal
요약하면 더블형 연산은 소수점 연산이 문제가 될 수 있으니, 정확한 소수점 연산을 위해서는 BigDecimal 클래스를 사용하라는 것이다.
예시를 보자.
Double d1 = 12345.12347986;
Double d2 = 41235.23498705;
System.out.println("d1 + d2 = " + (d1 + d2)); // d1 + d2 = 53580.358466909995
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);
System.out.println(bd1.add(bd2)); // 53580.35846691
Double형 변수들의 연산 결과는 예상했던 결과와 다른 것을 확인할 수 있다.
그러면 어떻게 BigDecimal 을 사용해야 할까?
BigDecimal
BigDecimal API Docs에 소개된 내용의 일부만을 기재합니다.
생성자
BigDecimal(BigInteger val)
- Translates a BigInteger into a BigDecimal.
this.paramVal = new BigDecimal(BigInteger.valueOf(100));
BigDecimal(BigInteger unscaledVal, int scale)
- Translates a BigInteger unscaled value and an int scale into a BigDecimal.
this.paramValAndScale = new BigDecimal(new BigInteger("-123456789"), 3);
BigDecimal(BigInteger unscaledVal, int scale, MathContext mc)
- Translates a BigInteger unscaled value and an int scale into a BigDecimal, with rounding according to the context settings.
this.paramValAndScaleAndMc = new BigDecimal(
new BigInteger("9876123"), 3,
new MathContext(7, RoundingMode.HALF_UP));
BigDecimal(BigInteger val, MathContext mc)
- Translates a BigInteger into a BigDecimal rounding according to the context settings.
this.paramValAndMc = new BigDecimal(
new BigInteger("12"),
new MathContext(1, RoundingMode.HALF_UP));
BigDecimal(String val)
- Translates the string representation of a BigDecimal into a BigDecimal.
this.paramString = new BigDecimal("100");
메소드
abs()
- Returns a BigDecimal whose value is the absolute value of this BigDecimal, and whose scale is this.scale().
System.out.println("abs() = " + this.paramValAndScale.abs());
add(BigDecimal augend)
Returns a BigDecimal whose value is (this + augend), and whose scale is max(this.scale(), augend.scale()).
System.out.println("add(BigDecimal augend) = " + this.paramVal.add(this.paramValAndScale));
compareTo(BigDecimal val)
Compares this BigDecimal with the specified BigDecimal.
System.out.println("compareTo(BigDecimal val) = " + this.paramVal.compareTo(this.paramValAndScale));
divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
Returns a BigDecimal whose value is (this / divisor), and whose scale is as specified.
System.out.println("divide(BigDecimal divisor, int scale, RoundingMode roundingMode) = " + this.paramVal.divide(new BigDecimal("13"), 3, RoundingMode.HALF_UP));
divideAndRemainder(BigDecimal divisor)
Returns a two-element BigDecimal array containing the result of divideToIntegralValue followed by the result of remainder on the two operands.
System.out.println("divideAndRemainder(BigDecimal divisor) = " + Arrays.toString(this.paramValAndScaleAndMc.divideAndRemainder(this.paramVal)));
max(BigDecimal val)
Returns the maximum of this BigDecimal and val.
System.out.println("max(BigDecimal val) = " + this.paramValAndScaleAndMc.max(this.paramVal));
min(BigDecimal val)
Returns the minimum of this BigDecimal and val.
System.out.println("min(BigDecimal val) = " + this.paramValAndScaleAndMc.min(this.paramVal));
pow(int n)
Returns a BigDecimal whose value is (thisn), The power is computed exactly, to unlimited precision.
System.out.println("pow(int n) = " + this.paramVal.pow(2));
setScale(int newScale, RoundingMode roundingMode)
Returns a BigDecimal whose scale is the specified value, and whose unscaled value is determined by multiplying or dividing this BigDecimal's unscaled value by the appropriate power of ten to maintain its overall value.
System.out.println("setScale(int newScale, RoundingMode roundingMode) = " + this.paramValAndScaleAndMc.setScale(5, RoundingMode.HALF_DOWN));
Full Source Code
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Arrays;
public class BigDecimalDemo {
private BigDecimal paramVal, paramValAndScale, paramValAndScaleAndMc, paramValAndMc, paramString;
public static void main(String[] args){
BigDecimalDemo demo = new BigDecimalDemo();
System.out.println("# operateDouble() ");
demo.operateDouble();
System.out.println("# ========== #");
System.out.println("# constructors() ");
demo.constructors();
System.out.println("# ========== #");
System.out.println("# methods() ");
demo.methods();
System.out.println("# ========== #");
}
private void operateDouble(){
Double d1 = 12345.12347986;
Double d2 = 41235.23498705;
System.out.println("d1 + d2 = " + (d1 + d2)); // d1 + d2 = 53580.358466909995
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);
System.out.println(bd1.add(bd2)); // 53580.35846691
}
/**
* BigDecimal(BigInteger val)
* Translates a BigInteger into a BigDecimal.
*
* BigDecimal(BigInteger unscaledVal, int scale)
* Translates a BigInteger unscaled value and an int scale into a BigDecimal.
*
* BigDecimal(BigInteger unscaledVal, int scale, MathContext mc)
* Translates a BigInteger unscaled value and an int scale into a BigDecimal, with rounding according to the context settings.
*
* BigDecimal(BigInteger val, MathContext mc)
* Translates a BigInteger into a BigDecimal rounding according to the context settings.
*
* BigDecimal(String val)
* Translates the string representation of a BigDecimal into a BigDecimal.
*/
private void constructors(){
// BigDecimal(BigInteger val)
this.paramVal = new BigDecimal(BigInteger.valueOf(100));
// BigDecimal(BigInteger unscaledVal, int scale)
this.paramValAndScale = new BigDecimal(new BigInteger("-123456789"), 3);
// BigDecimal(BigInteger unscaledVal, int scale, MathContext mc)
this.paramValAndScaleAndMc = new BigDecimal(
new BigInteger("9876123"), 3,
new MathContext(7, RoundingMode.HALF_UP));
// BigDecimal(BigInteger val, MathContext mc)
this.paramValAndMc = new BigDecimal(
new BigInteger("12"),
new MathContext(1, RoundingMode.HALF_UP));
// BigDecimal(String val)
this.paramString = new BigDecimal("100");
System.out.println("paramVal = " + this.paramVal);
System.out.println("paramValAndScale = " + this.paramValAndScale);
System.out.println("paramValAndScaleAndMc = " + this.paramValAndScaleAndMc);
System.out.println("paramValAndMc = " + this.paramValAndMc);
System.out.println("paramString = " + this.paramString);
}
/**
* abs()
* Returns a BigDecimal whose value is the absolute value of this BigDecimal, and whose scale is this.scale().
*
* add(BigDecimal augend)
* Returns a BigDecimal whose value is (this + augend), and whose scale is max(this.scale(), augend.scale()).
*
* compareTo(BigDecimal val)
* Compares this BigDecimal with the specified BigDecimal.
*
* divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
* Returns a BigDecimal whose value is (this / divisor), and whose scale is as specified.
*
* divideAndRemainder(BigDecimal divisor)
* Returns a two-element BigDecimal array containing the result of divideToIntegralValue followed by the result of remainder on the two operands.
*
* max(BigDecimal val)
* Returns the maximum of this BigDecimal and val.
*
* min(BigDecimal val)
* Returns the minimum of this BigDecimal and val.
*
* pow(int n)
* Returns a BigDecimal whose value is (thisn), The power is computed exactly, to unlimited precision.
*
* setScale(int newScale, RoundingMode roundingMode)
* Returns a BigDecimal whose scale is the specified value, and whose unscaled value is determined by multiplying or dividing this BigDecimal's unscaled value by the appropriate power of ten to maintain its overall value.
*/
private void methods(){
// abs()
System.out.println("abs() = " + this.paramValAndScale.abs());
// add(BigDecimal augend)
System.out.println("add(BigDecimal augend) = " + this.paramVal.add(this.paramValAndScale));
// compareTo(BigDecimal val)
System.out.println("compareTo(BigDecimal val) = " + this.paramVal.compareTo(this.paramValAndScale));
// divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
System.out.println("divide(BigDecimal divisor, int scale, RoundingMode roundingMode) = " + this.paramVal.divide(new BigDecimal("13"), 3, RoundingMode.HALF_UP));
// divideAndRemainder(BigDecimal divisor)
System.out.println("divideAndRemainder(BigDecimal divisor) = " + Arrays.toString(this.paramValAndScaleAndMc.divideAndRemainder(this.paramVal)));
// max(BigDecimal val)
System.out.println("max(BigDecimal val) = " + this.paramValAndScaleAndMc.max(this.paramVal));
// min(BigDecimal val)
System.out.println("min(BigDecimal val) = " + this.paramValAndScaleAndMc.min(this.paramVal));
// pow(int n)
System.out.println("pow(int n) = " + this.paramVal.pow(2));
// setScale(int newScale, RoundingMode roundingMode)
System.out.println("setScale(int newScale, RoundingMode roundingMode) = " + this.paramValAndScaleAndMc.setScale(5, RoundingMode.HALF_DOWN));
}
}
더 많은 내용을 보시려면 아래를 참고하세요.
https://docs.oracle.com/javase/8/docs/api/
https://madplay.github.io/post/the-need-for-bigdecimal-in-java
블로그의 다른 글
'[개발] 언어 > Java' 카테고리의 다른 글
외부 라이브러리의 thread-safety 확인하는 방법 (0) | 2022.03.24 |
---|---|
자바 애노테이션이란? (0) | 2022.03.24 |
The unknown errors occur in pom.xml when using STS4 (0) | 2019.08.03 |
Apache POI (0) | 2018.01.24 |
java - Generics & Wildcard (0) | 2017.12.16 |