자바 에서 BigDecimal 정밀도 문 제 를 상세 하 게 풀다.
9367 단어 자바bigdecimal정밀도
실제 개발 에 서 는 정밀 도 를 정확하게 계산 하지 않 아 도 되 는 속성 에 대해 서 는 float 나 double 을 직접 사용 할 수 있 으 나 정확 한 계산 결과 가 필요 하 다 면 가격,품질 등 BigDecimal 을 사용 해 야 한다.
왜 이렇게 말 합 니까?주로 두 가지 가 있 습 니 다.
1.double 계산 은 정밀도 손실 문제 가 있 습 니 다.
2.나눗셈 연산 시 BigDecimal 은 풍부 한 취사선택 규칙 을 제공 합 니 다.(double 은 NumberFormat 을 통 해 반올림 할 수 있 지만 NumberFormat 은 스 레 드 가 안전 하지 않 습 니 다)
정밀도 문제 에 대하 여 우 리 는 실제 의 예 를 볼 수 있다.
public static void main(String[] args) {
// 3.3
System.out.println(" :"+(1.1+2.2));
// -7.9
System.out.println(" :"+(2.2-10.1));
// 2.42
System.out.println(" :"+(1.1*2.2));
// 0.44
System.out.println(" :"+(4.4/10));
}
실제 콘 솔 출력왜 이러 니
우리 컴퓨터 는 2 진법 이다.부동 소수점 은 2 진법 으로 정확하게 표시 할 방법 이 없다.우리 의 CPU 는 부동 소수점 이 두 부분 으로 구성 되 어 있다 는 것 을 나타 낸다.지수 와 끝자리,이런 표현 방법 은 일반적으로 모두
일정한 정확 도 를 잃 으 면 일부 부동 소수점 연산 도 일정한 오차 가 생 길 수 있다.예 를 들 어 2.4 의 이 진 은 정확 한 2.4 가 아니 라 는 것 을 나타 낸다.오히려 가장 가 까 운 이 진 은 2.399999999999999999999 라 고 밝 혔 다.
부동 소수점 의 수 치 는 실제로 특정한 수학 공식 에 의 해 계산 된다.
2.BigDecimal 구조 함수
1.네 가지 구조 함수
BigDecimal(int) // 。
BigDecimal(double) // 。
BigDecimal(long) // 。
BigDecimal(String) // 。
이 몇 개 는 모두 자주 사용 하 는 구조 기 이 고 그들 이 돌아 오 는 대상 은 모두 BigDecimal 대상 이다.다시 말 해 빅 디 밀 대상 을 다른 유형의 대상 으로 바 꾸 는 것 은 다음 과 같은 몇 가 지 를 통 해 알 수 있다.
toString() // BigDecimal 。
doubleValue() // BigDecimal 。
floatValue() // BigDecimal 。
longValue() // BigDecimal 。
intValue() // BigDecimal 。
여 기 는 BigDecimal(double)의 구조 함수 에 매우 주의해 야 합 니 다.또한 정밀도 가 잃 어 버 리 는 문제 가 존재 할 수 있 습 니 다.다른 것 은 아 닙 니 다.여기 서도 예 를 들 어 설명 할 수 있 습 니 다.
public static void main(String[] args) {
BigDecimal intDecimal = new BigDecimal(10);
BigDecimal doubleDecimal = new BigDecimal(4.3);
BigDecimal longDecimal = new BigDecimal(10L);
BigDecimal stringDecimal = new BigDecimal("4.3");
System.out.println("intDecimal=" + intDecimal);
System.out.println("doubleDecimal=" + doubleDecimal);
System.out.println("longDecimal=" + longDecimal);
System.out.println("stringDecimal=" + stringDecimal);
}
콘 솔 실제 출력그림 에서 볼 수 있 듯 이 double 의 구조 함수 에 대해 정밀도 가 잃 어 버 릴 가능성 이 있다.
2,왜 이런 상황
이것 은 new BigDecimal(double)유형의 구조 함수 에 대한 설명 이 있 습 니 다.
이 구조 함수 의 결 과 는 예측 할 수 없 을 것 이다.자바 에 new BigDecimal(0.1)을 기록 하여 BigDecimal 을 만 들 었 다 고 가정 할 수 있 습 니 다.이것 은 완전히 0.1(비 눈금 값 은 1,비례 는 1)과 같 지만 사실은 같 습 니 다.
0.1000000000000000055511151231257827021181583404541015625。 0.1 이 더 블(또는 그 어떠한 제 한 된 길이 의 이 진 점수)처럼 정확하게 표시 할 수 없 기 때문이다.
따라서 구조 에 전달 되 고 있 는 값 은 0.1 이 아니다.
3.어떻게 해결 할 것 인가
두 가지 상용 해결 방법 이 있다.
1.double.toString(double)을 통 해 먼저 String 으로 전환 한 다음 에 BigDecimal 의 String 구조 함수 에 넣 습 니 다.
2.BigDecimal 의 구조 함 수 를 통과 하지 않 고 정적 인 방법 인 BigDecimal.valueOf(double)를 통 해서 도 정밀 도 를 잃 지 않 습 니 다.
예시
public static void main(String[] args) {
String string = Double.toString(4.3);
BigDecimal stringBigDecimal = new BigDecimal(string);
BigDecimal bigDecimal = BigDecimal.valueOf(4.3);
System.out.println("stringBigDecimal = " + stringBigDecimal);
System.out.println("bigDecimal = " + bigDecimal);
}
실행 결과이렇게 하면 더 블 에 게 빅 데 시 멜 을 돌리 면 정밀도 가 떨 어 지지 않 는 다 는 것 을 보증 할 수 있다.
3.상용 방법
1.상용 방법
예시
public static void main(String[] args) {
BigDecimal a = new BigDecimal("4.5");
BigDecimal b = new BigDecimal("1.5");
BigDecimal c = new BigDecimal("-10.5");
BigDecimal add_result = a.add(b);
BigDecimal subtract_result = a.subtract(b);
BigDecimal multiply_result = a.multiply(b);
BigDecimal divide_result = a.divide(b);
BigDecimal remainder_result = a.remainder(b);
BigDecimal max_result = a.max(b);
BigDecimal min_result = a.min(b);
BigDecimal abs_result = c.abs();
BigDecimal negate_result = a.negate();
System.out.println("4.5+1.5=" + add_result);
System.out.println("4.5-1.5=" + subtract_result);
System.out.println("4.5*1.5=" + multiply_result);
System.out.println("4.5/1.5=" + divide_result);
System.out.println("4.5/1.5 =" + remainder_result);
System.out.println("4.5 1.5 =" + max_result);
System.out.println("4.5 1.5 =" + min_result);
System.out.println("-10.5 =" + abs_result);
System.out.println("4.5 =" + negate_result);
}
4.5+1.5=6.04.5-1.5=3.0
4.5*1.5=6.75
4.5/1.5=3
4.5/1.5 여수=0.0
4.5 와 1.5 최대 수=4.5
4.5 와 1.5 최 소수=1.5
-10.5 의 절대 치=10.5
4.5 의 반대 수=-4.5
여기 서 나눗셈 을 따로 다시 한 번 말씀 드 리 겠 습 니 다.나눗셈 을 조작 할 때 다 제거 할 수 없 는 상황 이 있 기 때 문 입 니 다.예 를 들 어 3,5/3,이때 자바.lang.Arithmetic Exception:Non-terminating decimal expansion 을 잘못 보고 할 수 있 습 니 다.
no exact representable decimal result。그래서 여 기 는 끝 이 없 는 상황 에서 몇 개의 소수,취사 규칙 을 보류 하 는 것 을 고려 해 야 한다.나눗셈 이 들 어가 지 않 을 수 있다 면 다음 방법 을 사용 하 세 요)
BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) , , 。
2.취사선택 규칙
ROUND_UP // (0 ) 1
ROUND_DOWN // ,
ROUND_HALF_UP //
ROUND_HALF_DOWN //
ROUND_CEILING //
ROUND_FLOOR //
ROUND_HALF_EVEN // ( ) , ( ) , , , ROUND_HALF_UP, , ROUND_HALF_DOWN
ROUND_UNNECESSARY // ,
주의 하 세 요.저희 가 제일 많이 쓰 는 건 ROUND 인 것 같 아 요.HALF_UP(반올림)여기 서 자주 사용 하 는 취사선택 규칙 을 몇 개 들 었 다.
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1.15");
BigDecimal b = new BigDecimal("1");
// (0 ) 1 1.2
BigDecimal divide_1 = a.divide(b,1,BigDecimal.ROUND_UP);
// , 1.1
BigDecimal divide_2 = a.divide(b,1,BigDecimal.ROUND_DOWN);
// 1.2
BigDecimal divide_3 = a.divide(b,1,BigDecimal.ROUND_HALF_UP);
// 1.1
BigDecimal divide_4 = a.divide(b,1,BigDecimal.ROUND_HALF_DOWN);
// 1.15 1.16
BigDecimal c = new BigDecimal("1.16");
// 1.2
BigDecimal divide_5 = c.divide(b,1,BigDecimal.ROUND_HALF_DOWN);
System.out.println("divide_1 = " + divide_1);
System.out.println("divide_2 = " + divide_2);
System.out.println("divide_3 = " + divide_3);
System.out.println("divide_4 = " + divide_4);
System.out.println("divide_5 = " + divide_5);
}
실행 결과divide_1 = 1.2
divide_2 = 1.1
divide_3 = 1.2
divide_4 = 1.1
divide_5 = 1.2
포맷
NumberFormat 류 의 format()방법 은 BigDecimal 대상 을 매개 변수 로 사용 할 수 있 기 때문에 BigDecimal 을 이용 하여 16 비트 이상 의 유효 숫자 를 가 진 화폐 값,백분 치,일반 수 치 를 포맷 제어 할 수 있 습 니 다.
BigDecimal 을 이용 하여 화폐 와 백분율 을 포맷 하 는 것 을 예 로 들 면.우선,BigDecimal 대상 을 만 들 고 BigDecimal 의 산술 연산 을 한 후 각각 화폐 와 백분율 포맷 에 대한 인용 을 만 들 고 마지막 으로 이용 합 니 다.
BigDecimal 대상 은 format()방법의 매개 변수 로 포맷 된 화폐 값 과 백분율 을 출력 합 니 다.
예시
public static void main(String[] args) {
//
NumberFormat currency = NumberFormat.getCurrencyInstance();
//
NumberFormat percent = NumberFormat.getPercentInstance();
// 3
percent.setMaximumFractionDigits(3);
//
NumberFormat integerInstance = NumberFormat.getIntegerInstance();
////
BigDecimal loanAmount = new BigDecimal("188.555");
////
BigDecimal interestRate = new BigDecimal("0.018555555");
// 2
System.out.println(" : " + currency.format(loanAmount));
// ( )
System.out.println(" : " + percent.format(interestRate));
// 188.555 189, 188.51 189 189.5 188,
System.out.println(" : " + integerInstance.format(loanAmount));
}
실행 결과금액:¥188.56 금 리:1.856%취 정:189
여기 몇 가지 설명 이 있어 요.
1.포맷 할 때 보존 자릿수 가 지정 되 지 않 은 상태 에서 기본적으로 2 자 리 를 유지 합 니 다.
2.화폐(백분율)포맷 지정 기본 취사 규칙 은 반올림 입 니 다.
3.취 정 은 조금 다 릅 니 다.188.555 취 정 은 189 이 고 188.51 도 189 입 니 다.그러나 189.5 는 확실히 188 이기 때문에 진정한 의미 의 반올림 이 아 닙 니 다.
이상 은 자바 에서 BigDecimal 정밀도 문 제 를 상세 하 게 설명 하 는 상세 한 내용 입 니 다.자바 에 관 한 자 료 는 다른 관련 글 에 주목 하 세 요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.