2014-12-04 1 views
0

스트럿에 두 개의 필드가 형성 등 :BigDecimal를 분할 문제

<c:set var="totalQuota" 
value="${(strutsForm.totalQuota div 1024 div 1024 div 1024)}"></c:set> 
${ ((strutsForm.currentUsage div 1024 div 1024) div (totalQuota)) * 100 } 

그러나 출력 :

Long currentUsage; // 209715200l 
BigDecimal totalQuota; // 343597383680 

나뿐만 비율을 표시 을 사용하고 JSP 에 표시되는 값은 입니다.
왜 이런 일이 발생하고 있습니까? 어떻게 적절한 결과를 얻을 수 있습니까?

+0

내가 가장 쉬운 해결책은 바로 서버 측에서이 계산을하고보기 페이지에서 결과를 사용하는 것입니다 생각합니다. –

+0

@SemihEker : 당신 말이 맞아요. 하지만 jsp에서도 할 수 있는지를 찾고 있습니다. –

답변

1

왜 이런 일이 발생합니까?

이 카운터 직관 동작이지만, I는 즉,의 BigDecimal에 변수 강제 분할에 대한 EL 사양 (LInk to oracle EL spec)는, 수행되는 방식이다라고 생각한다.

코드의 첫 번째 줄 :

${(strutsForm.totalQuota div 1024 div 1024 div 1024)} 

번째 행을 BigDecimal를

을 totalQuota에게 BigDecimal를 행 1024의 값을 강요하고 반환하는 동작을 수행한다

${ ((strutsForm.currentUsage div 1024 div 1024) div (totalQuota)) * 100 } 

것 먼저 currentUsage를 Double에 강요하고 1024 * 1024로 나누어 Double을 반환합니다. BigDecimal에 강요 (totalQuota가 BigDecimal이기 (위해) 때문에, A.divide(B, BigDecimal.ROUND_HALF_UP)를 실행한다). 이것의 결과는, BigDecimal 변수의 스케일에 의존합니다 (소수점 이하 자리 올림에 영향을줍니다). 둘 중 하나가 스케일 0이면이 반올림은 사용자가보고있는 정수 결과 (100을 곱한 값)가됩니다.

다음 일반 자바 단계와 결과에 의해 단계에 무슨 일이 일어나고 있는지 보여줍니다

public class jsp_problem_steps 
{ 
    public static void main(String[] args) 
    { 
    Long currentUsage=209715200l; // 209715200l 
    BigDecimal totalQuota = new BigDecimal("343597383680"); // 343597383680 

    BigDecimal coerced = new BigDecimal("1024"); 

    BigDecimal t = totalQuota.divide(coerced, BigDecimal.ROUND_HALF_UP).divide(coerced, BigDecimal.ROUND_HALF_UP).divide(coerced, BigDecimal.ROUND_HALF_UP); 
    System.out.println("coerced BigDecimal quota : " + t); 

    Double d = currentUsage.doubleValue()/1024d/1024d; 

    System.out.println("coerced Double usage : " + d); 

    BigDecimal coerced_d = (new BigDecimal(d)); 

    System.out.println(coerced_d + " at scale " + coerced_d.scale()); 

    BigDecimal res = coerced_d.divide(t,BigDecimal.ROUND_HALF_UP); 

    System.out.println("Result of division : " + res + " THIS IS UNEXPECTED!!!"); 

    res = res.multiply(new BigDecimal("100")); 

    System.out.println("Final value : " + res); 
    } 
} 

출력을 제공합니다

coerced BigDecimal quota : 320 
coerced Double usage : 200.0 
200 at scale 0 
Result of division : 1 THIS IS UNEXPECTED!!! 
Final value : 100 

문제 단계 BigDecimal coerced_d = (new BigDecimal(d));입니다 : BigDecimal를 더블의 강제 수행되고 규모가 0 인 BigDecimal을 제공하는 BigDecimal 생성자를 사용합니다. 예를 들어 BigDecimal coerced_d = (new BigDecimal(d.toString()));을 사용하여 구성을 완료 한 경우 예상되는 값을 얻을 수 있습니다 (즉, 나누기의 결과로 0.625가 표시되고 62.5가 표시됨)

이것이 예상되는 동작인지 버그인지는 논란의 여지가 있습니다. Double에서 BigDecimal로 강제 변환하는 방법을 사양에서 분명히 알 수 없습니다.

어떻게하면 적절한 결과를 얻을 수 있습니까?

변경 마지막 줄에 :을 BigDecimal에 더블의 문제 강압을 피해야한다

${ ((strutsForm.currentUsage div 1024 div 1024) div (totalQuota.doubleValue())) * 100 } 

. 나는 시험 할 환경이 없기 때문에 그것이 작동 할 것이라고 확신 할 수는 없지만, 그렇게 보인다.