간단히 대답하면 표현 오류와 부동 소수점 연산에 대한 반올림 오류가 있다는 것입니다. toString()
은 표현 오류에 대해 "인식"하므로 반올림 오류가없는 경우에는 표시되지 않습니다. 그러나 반올림 오류가 너무 크면 수행 할 수 있습니다.
해결책은 BigDecimal을 사용하거나 결과를 반올림하는 것입니다.
BigDecimal을 사용하는 경우 실제 값이 정확하게 표시됩니다.
double d = 0.3d;
double f = 0.1d;
System.out.println("d= " + new BigDecimal(d));
System.out.println("f= " + new BigDecimal(f));
System.out.println("d+f= " + new BigDecimal(d + f));
System.out.println("0.4= " + new BigDecimal(0.4));
System.out.println("d*f= " + new BigDecimal(d * f));
System.out.println("0.03= " + new BigDecimal(0.03));
System.out.println("d-f= " + new BigDecimal(d - f));
System.out.println("0.2= " + new BigDecimal(0.2));
System.out.println("d/f= " + new BigDecimal(d/f));
System.out.println("(d-f)*(d-f)= " + new BigDecimal((d - f) * (d - f)));
인쇄
d= 0.299999999999999988897769753748434595763683319091796875
f= 0.1000000000000000055511151231257827021181583404541015625
d+f= 0.40000000000000002220446049250313080847263336181640625
0.4= 0.40000000000000002220446049250313080847263336181640625
d*f= 0.0299999999999999988897769753748434595763683319091796875
0.03= 0.0299999999999999988897769753748434595763683319091796875
d-f= 0.1999999999999999833466546306226518936455249786376953125
0.2= 0.200000000000000011102230246251565404236316680908203125
d/f= 2.999999999999999555910790149937383830547332763671875
(d-f)*(d-f)= 0.03999999999999999389377336456163902767002582550048828125
당신은 0.1
약간 너무 커서 0.3
약간 너무 작다는 것을 알 수 있습니다. 이것은 당신이 그들을 더하거나 증식 할 때 당신은 대략 옳은 숫자를 얻는다는 것을 의미합니다. 그러나 빼기 또는 나눗셈을 사용하면 오류가 누적되고 표현 된 수와 너무 먼 수를 얻습니다.
즉 0.1과 0.3은 0.4와 동일한 값을 갖지만 0.3 - 0.1은 0과 같은 값을 갖지 않습니다.BTW
2는
d-f= 0.20
d/f= 3.00
(d-f)*(d-f)= 0.04
또는
System.out.println("d-f= " + roundTo6Places(d - f));
System.out.println("d/f= " + roundTo6Places(d/f));
System.out.println("(d-f)*(d-f)= " + roundTo6Places((d - f) * (d - f)));
public static double roundTo6Places(double d) {
return (long)(d * 1e6 + (d > 0 ? 0.5 : -0.5))/1e6;
}
인쇄
System.out.printf("d-f= %.2f%n", d - f);
System.out.printf("d/f= %.2f%n", d/f);
System.out.printf("(d-f)*(d-f)= %.2f%n", (d - f) * (d - f));
인쇄를 사용할 수의 BigDecimal을 사용하지 않고 답을 반올림합니다
System.out.println("d-f= " + roundTo6Places(d - f));
System.out.println("d/f= " + roundTo6Places(d/f));
System.out.println("(d-f)*(d-f)= " + roundTo6Places((d - f) * (d - f)));
라운딩 전에 0.1 후에 표현 될 수있는 값
double before_f = Double.longBitsToDouble(Double.doubleToLongBits(f) - 1);
System.out.println("The value before 0.1 is " + new BigDecimal(before_f) + " error= " + BigDecimal.valueOf(0.1).subtract(new BigDecimal(before_f)));
System.out.println("The value after 0.1 is " + new BigDecimal(f) + " error= " + new BigDecimal(f).subtract(BigDecimal.valueOf(0.1)));
같이 계산 될 수
(의하여 toString 처리하도록 설계 만 표시 오차를 떠나) 라운딩 에러를 제거
인쇄
The value before 0.1 is 0.09999999999999999167332731531132594682276248931884765625
error= 8.32667268468867405317723751068115234375E-18
The value after 0.1 is 0.1000000000000000055511151231257827021181583404541015625
error= 5.5511151231257827021181583404541015625E-18
가장 많이 묻는 질문 중 하나이다. 컴퓨팅에 대한 질문에 대답했습니다. : P –
... 그리고 on Stackoverflow – Thilo
귀하의 질문에 첫 번째 문장은 대답을 것 같습니다! – assylias