为什么使用add2
方法的结果是错误的?Double.toString(d1)
为什么能保持double
的精度不丢失?
public static double add(double d1, double d2) {
BigDecimal bd1 = new BigDecimal(Double.toString(d1));
BigDecimal bd2 = new BigDecimal(Double.toString(d2));
return bd1.add(bd2).doubleValue();
}
public static double add2(double d1, double d2) {
BigDecimal bd1 = new BigDecimal(d1);
BigDecimal bd2 = new BigDecimal(d2);
return bd1.add(bd2).doubleValue();
}
public static void main(String[] args) {
double d1 = 1.0000002;
double d2 = 0.0000002;
System.out.println(Double.toString(d1));
System.out.println("d1 + d2 = " + (d1 + d2)); // 1.0000003999999998
System.out.println("d1 + d2 = " + add(d1, d2)); // 1.0000004
System.out.println("d1 + d2 = " + add2(d1, d2)); // 1.0000003999999998
}
PS:引出一个概念问题:
double d = XXXX.XXXXXX;
System.out.println(d); //这里总是不会丢失精度的,为什么?
BigDecimal이 double을 입력 매개변수로 사용하는 경우 바이너리는 십진수를 정확하게 표현할 수 없습니다. 컴파일러는 "0.0000002" 및 "1.0000002" 문자열을 읽은 후 이를 8바이트 double 값으로 변환해야 합니다.
1.0000001999999998947288304407265968620777130126953125
.따라서 실행 시 실제로 BigDecimal 생성자에 전달되는 실제 값은
1.0000001999999998947288304407265968620777130126953125
입니다.BigDecimal은 문자열을 입력 매개변수로 사용할 때 문자열을 매우 정확한 부동 소수점 숫자로 올바르게 변환할 수 있습니다.
System.out.println 부분에서 입력 매개변수가 string이면 직접 출력하고, 입력 매개변수가 다른 유형이면 Object.toString 메소드를 호출하여 변환한 후 출력합니다. Double.toString은 특정 정밀도를 사용하여 double을 출력하기 전에 반올림합니다.
BigDecimal 생성자에 대한 설명에서 이 문제를 다룹니다.
으아악추가 설명:
으아악Double.toString
이 메서드는String
을 출력하고 반올림됩니다.new BigDecimal(Double.toString(d1))
입력 매개변수는 처리 후String
이며BigDecimal(String val)
생성자가 호출됩니다.소스 코드의 BigDecimal(String val) 메소드는 val을 char[] 배열로 처리합니다.
그런 다음
BigDecimal(char[] in)
생성자를 호출합니다.그리고 새로운 BigDecimal(d1)은
입니다. 으아악BigDecimal(double val)
을 호출합니다. 이 메소드가 들어온 후 가장 먼저 나오는 것은입력 매개변수를 바이너리로 변환하면 정확도가 떨어집니다.
이중 덧셈으로 인한 정밀도 손실은 위의 상황과 동일합니다. 먼저 비트로 변환한 후 계산한 다음 정밀도를 잃습니다. .