자바 수치 범위 및 float 와 double 정밀도 손실 문제 해결
public class TestOutOfBound {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE-(-Integer.MAX_VALUE)); //
System.out.println(Integer.MAX_VALUE); //2 31 -1,10 , 20 ,
System.out.println(Integer.MIN_VALUE); // 2 31
System.out.println(Long.MAX_VALUE); //2 64 -1,19 , ,
System.out.println(Long.MIN_VALUE); // 2 64
System.out.println(Float.MAX_VALUE); //2 128 -1,38 , long ,
System.out.println(Float.MIN_VALUE); //2 -149
System.out.println(Double.MAX_VALUE); //2 1024 -1,308 , float 10 ,
System.out.println(Double.MIN_VALUE); //2 -1074
}
}
2.float 와 double 정밀도 손실 문제예:
:double result = 1.0 - 0.9;
, ,0.09999999999999998
왜 이 문제 가 발생 했 습 니까?이것 은 자바 와 다른 컴퓨터 언어 에서 모두 발생 할 수 있 는 문제 입 니 다.다음은 왜 이 문제 가 발생 했 는 지 분석 해 보 겠 습 니 다.float 와 double 유형 은 주로 과학적 계산 과 공정 계산 을 위해 설계 되 었 다.그들 은 이 진 부동 소수점 연산 을 집행 하 는데 이것 은 광범 위 한 디지털 범위 에서 비교적 정확 하고 빠 른 유사 계산 을 제공 하기 위해 심혈 을 기울 여 설계 한 것 이다.그러나 이들 은 정확 한 결 과 를 제공 하지 않 았 기 때문에 우 리 는 정확 한 계산 장소 에 사용 해 서 는 안 된다.float 와 double 유형 은 특히 화폐 연산 에 적합 하지 않 습 니 다.float 나 double 이 0.1 또는 10 의 다른 마이너스 제곱 값 을 정확하게 표시 하 는 것 은 불가능 하기 때 문 입 니 다.마찬가지 로 이 진 시스템 도 1/10 을 정확하게 표시 할 수 없다.
부동 소수점 연산 은 매우 정확 하지 않 고 정밀도 가 표시 할 수 있 는 범 위 를 초과 하면 오차 가 발생 할 수 있다.흔히 오차 가 발생 하 는 것 은 수의 크기 때 문 이 아니 라 수의 정밀도 때문이다.따라서 결과 가 비슷 하지만 원 하 는 결 과 는 아니다.특히 float 와 double 을 사용 하여 정확 한 연산 을 할 때 특히 조심해 야 한다.
지금 우 리 는 부동 소수점 형 연산 이 왜 정밀도 손실 을 초래 하 는 지 상세 하 게 분석 해 보 자.
:
(1)
。 ,11 :
11/2=5 1
5/2=2 1
2/2=1 0
1/2=0 1
0 11 ( ):1011
: 0 , , 2 0。 , ? , , 。
(2)
2 。 ,0.9
0.9*2=1.8 1
0.8(1.8 )*2=1.6 1
0.6*2=1.2 1
0.2*2=0.4 0
0.4*2=0.8 0
0.8*2=1.6 1
0.6*2=1.2 0
......... 0.9 ( ): 1100100100100......
: , *2 , 。 , 。 , 1/3 ? 1/10。 " " 。
3.해결 방법 1:만약 에 자신 이 십 진법 의 소수점 을 기록 하 는 것 을 개의 치 않 고 수치 가 크 지 않다 면 롱,int 등 기본 유형 을 사용 할 수 있다.구체 적 으로 int 를 사용 하 느 냐 롱 을 사용 하 느 냐 와 관련 된 수치 범위 의 크기 를 봐 야 한다.단점 은 십 진법 소수점 을 스스로 처리 해 야 한 다 는 것 이다.가장 뚜렷 한 방법 은 화폐 사용 점 수 를 처리 하여 계산 하 는 것 이지 원(가감 만 관련)을 사용 하지 않 는 것 이다.
예:
int resultInt = 10 - 9;
double result = (double) resultInt / 100;//
4.해결 방법 2:BigDecmal 을 사용 하고 구조 적 매개 변수 에 String 형식 을 사용 해 야 합 니 다.
'Effective Java'라 는 책 에서 해결책 을 제시 했다.이 책 에서 도 플 로 트 와 더 블 은 과학적 계산 이나 공정 계산 에 만 사용 할 수 있 고 상업 계산 등 정확 한 계산 에서 우 리 는 자바.math.BigDecimal 을 사용 해 야 한다 고 지적 했다.
BigDecimal 류 는 네 가지 방법 이 있 는데 우 리 는 부동 소수점 데 이 터 를 정확하게 계산 하 는 데 유용 한 방법 에 만 관심 을 가진다.즉,
BigDecimal(double value)//double 형 데 이 터 를 BigDecimal 형 데이터 로 변환 합 니 다.
사고방식 은 매우 간단 하 다.우 리 는 먼저 BigDecimal(double value)방법 을 통 해 double 형 데 이 터 를 BigDecimal 데이터 로 변환 한 다음 에 정상적으로 정확하게 계산 할 수 있다.계산 이 끝 난 후에 우 리 는 결 과 를 처리 할 수 있다.예 를 들 어 다 하지 못 한 결 과 를 반올림 할 수 있다.마지막 으로 결 과 를 BigDecimal 형 데이터 에서 double 형 데이터 로 변환 합 니 다.
이 생각 은 매우 정확 하지만 API 에서 BigDecimal 에 관 한 상세 한 설명 을 자세히 보면 정확 한 계산 이 필요 하 다 면 우 리 는 String 으로 BigDecimal 을 구성 하지 않 으 면 안 된다 는 것 을 알 게 될 것 입 니 다!그래서 우 리 는 BigDecimal 류 의 또 다른 방법,즉 정확 한 계산 을 할 수 있 는 BigDecimal(String value)방법 에 관심 을 가지 기 시작 했다.
//BigDecimal(String value)은 String 형 데 이 터 를 BigDecimal 형 데이터 로 변환 할 수 있 습 니 다.
그러면 문제 가 생 겼 습 니 다.상상 해 보 세 요.만약 에 우리 가 부동 소수점 데이터 의 덧셈 연산 을 하려 면 먼저 두 개의 부동 소수점 을 String 형 데이터 로 바 꾼 다음 에 BigDecimal(String value)로 BigDecimal 로 구성 한 다음 에 그 중 하나 에서 add 방법 을 호출 하여 다른 하 나 를 매개 변수 로 전달 한 다음 에 연산 결과(BigDecimal)를 부동 소수점 으로 바 꿔 야 합 니 다.만약 매번 부동 소수점 데이터 의 계산 을 할 때마다 이렇게 해 야 한다 면,당신 은 이렇게 번 거 로 운 과정 을 참 을 수 있 습 니까?적어도 난 못 해.그래서 가장 좋 은 방법 은 바로 종 류 를 써 서 이런 번 거 로 운 전환 과정 을 완성 하 는 것 이다.이렇게 해서 우리 가 부동 소수점 데이터 계산 을 해 야 할 때 이 종 류 를 호출 하면 된다.인터넷 상에 서 이미 고수 가 우리 에 게 이러한 전환 작업 을 완성 하기 위해 도구 류 Arith 를 제공 했다.이 는 다음 과 같은 정적 방법 을 제공 하여 부동 소수점 데이터 의 덧셈 과 곱셈 연산 을 완성 하고 그 결 과 를 반올림 하 는 작업 을 할 수 있 습 니 다.
public static double add(double v1,double v2)
public static double sub(double v1,double v2)
public static double mul(double v1,double v2)
public static double div(double v1,double v2)
public static double div(double v1,double v2,int scale)
public static double round(double v,int scale)
다음은 Arith 의 소스 코드 를 첨부 합 니 다.컴 파일 을 잘 저장 하고 부동 소수점 계산 을 하려 면 원본 프로그램 에서 Arith 류 를 가 져 오 면 상기 정적 방법 으로 부동 소수점 을 정확하게 계산 할 수 있 습 니 다.
부록:Arith 소스 코드
import java.math.BigDecimal;
/**
* Java ,
* , 。
*/
public class Arith{
//
private static final int DEF_DIV_SCALE = 10;
//
private Arith(){
}
/**
* 。
* @param v1
* @param v2
* @return
*/
public static double add(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
/**
* 。
* @param v1
* @param v2
* @return
*/
public static double sub(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
/**
* 。
* @param v1
* @param v2
* @return
*/
public static double mul(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
* ( ) , ,
* 10 , 。
* @param v1
* @param v2
* @return
*/
public static double div(double v1,double v2){
return div(v1,v2,DEF_DIV_SCALE);
}
/**
* ( ) 。 , scale
* , 。
* @param v1
* @param v2
* @param scale 。
* @return
*/
public static double div(double v1,double v2,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 。
* @param v
* @param scale
* @return
*/
public static double round(double v,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
};
이상 자바 수치 범위 및 float 와 double 정밀도 손실 문 제 를 해결 하 는 것 은 바로 소 편 이 여러분 에 게 공유 하 는 모든 내용 입 니 다.참고 하 시기 바 랍 니 다.여러분 들 도 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Float 계산 회로의 Verilog-HDL 구현에 대해 - 그 2.7 (0 대응)~ FPGA에 올리고 싶다 ~ 올레올레 구현이므로 잘못되어도 몰라요 가산회로편 디버그 툴 작성편 보충과 LeadingZeros편 감산회로편 회로 공통화와 타이밍 조정편 공통화편 float 공부 float32의 하드웨...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.