2011-08-19 2 views
4

반올림에 문제가 있습니다. 특히, 모든 자바 독을 읽은 후, 나는 다음과 같은 코드를 기다리고 있었다 :java.math.RoundingMode는 어떻게 작동합니까?

int n = (integer between 0 and 9, included) 
new BigDecimal(n + 0.555d).setScale(2, RoundingMode.HALF_UP).doubleValue() 

n + 0.56를 반환 할 수 있습니다. 대신, 이들은 04까지 n의 반환 값은 다음과 같습니다

int n = (integer between 0 and 9, included) 
new BigDecimal(n + 0.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue() 

각각의 모든 n에 대한 결과로 n + 0.55을 기대 :

new BigDecimal(0.555d).setScale(2, RoundingMode.HALF_UP).doubleValue() 
0.56 
new BigDecimal(1.555d).setScale(2, RoundingMode.HALF_UP).doubleValue() 
1.55 
new BigDecimal(2.555d).setScale(2, RoundingMode.HALF_UP).doubleValue() 
2.56 
new BigDecimal(3.555d).setScale(2, RoundingMode.HALF_UP).doubleValue() 
3.56 
new BigDecimal(4.555d).setScale(2, RoundingMode.HALF_UP).doubleValue() 
4.55 

나는 또한 반올림 모드를 변경하기 위해 노력했다. 대신 반환 값은 이전 예제와 정확히 동일합니다.

new BigDecimal(0.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue() 
0.56 
new BigDecimal(1.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue() 
1.55 
new BigDecimal(2.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue() 
2.56 
new BigDecimal(3.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue() 
3.56 
new BigDecimal(4.555d).setScale(2, RoundingMode.HALF_DOWN).doubleValue() 
4.55 

누락 된 부분이 있습니까?

답변

7

문제는 두 배로 정확한 표현이 아니며이 부정확 한 숫자를 기준으로 계산 한 것입니다.

BigDecimal bd = new BigDecimal(1.555d); 
System.out.println("bd=" + bd); 
bd = bd.setScale(2, RoundingMode.HALF_UP); 
System.out.println("after rounding bd=" + bd); 
double d = bd.doubleValue(); 
System.out.println("after rounding d=" + d); 

인쇄

그러나

BigDecimal bd = BigDecimal.valueOf(1.555d); 
System.out.println("bd=" + bd); 
bd = bd.setScale(2, RoundingMode.HALF_UP); 
System.out.println("after rounding bd=" + bd); 
double d = bd.doubleValue(); 
System.out.println("after rounding d=" + d); 

인쇄

bd=1.555 
after rounding bd=1.56 
after rounding d=1.56 

BigDecimal.valueOf 당신이 인쇄 된 경우 어떻게 나타나는지 이중에 따라 몇 가지 추가 라운딩을 수행하기 때문에이 작동

bd=1.5549999999999999378275106209912337362766265869140625 
after rounding bd=1.55 
after rounding d=1.55 

그것.


성능/단순성이 문제가 아니라면 BigDecimal을 사용하지 않을 것입니다.

double d = 1.555d; 
System.out.println("d=" + d); 
d = roundToTwoPlaces(d); 
System.out.println("after rounding d=" + d); 

public static double roundToTwoPlaces(double d) { 
    return ((long) (d < 0 ? d * 100 - 0.5 : d * 100 + 0.5))/100.0; 
} 

인쇄 자세한 내용은 Double your money again를 들어

d=1.555 
after rounding d=1.56 

은 라운딩의 다른 방법의 성능을 비교한다.

+0

대단히 감사합니다. 나는 뭔가를 잊고 있었지만 문제를 지적 할 수는 없었습니다. – ilCatania

1

0.555ddouble 값입니다. 0.555보다 약간 크거나 약간 작을 수 있습니다.

0

10 진수를 반올림하기 위해 반올림 모드를 사용합니다.

함께 사용할 수 있습니다.

double DecimalValue = 3.1452; 
BigDecimal decimal = new BigDecimal(DecimalValue).setScale(2, RoundingMode.DOWN); 

=>

RoundingMode.CEILING 

라운딩 모드는 무한대에 가까워 지도록한다. 양수 값의 경우이 반올림 모드는 음수 값이 DOWN 인 경우 UP으로 동작합니다. 규칙 : 값이 0에 가까워 반올림 x.round() >= x

RoundingMode.DOWN 

라운딩 모드. 규칙 : x.round().abs() <= x.abs()

RoundingMode.DOWN 

부의 무한대에 가까워 지도록 마는 모드입니다. 양수 값의 경우이 반올림 모드는 음수 값이 UP 인 경우 DOWN으로 동작합니다. 규칙 : 값이 가장 가까운 이웃으로 반올림됩니다 x.round() <= x

RoundingMode.HALF_DOWN 

마는 모드입니다. 동점은 반올림하여 깨집니다.

RoundingMode.HALF_EVEN 

하는 값이 가장 가까운 이웃 향해 둥글게 라운딩 모드. 심지어 이웃으로 반올림하여 관계가 깨집니다.

RoundingMode.HALF_UP 

하는 값이 가장 가까운 이웃 향해 둥글게 라운딩 모드. 동점은 반올림하여 부러집니다. 라운딩 연산은 라운딩 경우의 ArithmeticException을 발생

RoundingMode.UNNECESSARY 

라운딩 모드 값 정확히 나타낼 수없는 경우에 필요 , 즉이다.

RoundingMode.UP 

은 양의 값이 무한대 음의 무한대에 가까워 음수 값으로 을 둥글게 라운딩 모드. 규칙 : x.round().abs() >= x.abs()