我的 struts表单中有两个字段:
Long currentUsage; // 209715200l
BigDecimal totalQuota; // 343597383680
在 jsp 上我使用el将百分比显示为:
<c:set var="totalQuota"
value="${(strutsForm.totalQuota div 1024 div 1024 div 1024)}"></c:set>
${ ( (strutsForm.currentUsage div 1024 div 1024) div (totalQuota) ) * 100 }
但显示的输出是 100 为什么会这样?我怎么能得到正确的结果?
答案 0 :(得分:1)
为什么会这样?
这是违反直觉的行为,但我认为这是用于除法的EL规范(LInk to oracle EL spec)的方式,即将变量强制转换为BigDecimal。
代码的第一行:
${(strutsForm.totalQuota div 1024 div 1024 div 1024)}
会将totalQuota的1024个值强制转换为BigDecimal,然后执行操作,返回BigDecimal
第二行
${ ( (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)。
以下普通Java显示了一步一步的结果和结果
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构造函数来完成Double to BigDecimal的强制,该构造函数为BigDecimal提供了比例0.如果构造是使用,比如说BigDecimal coerced_d = (new BigDecimal(d.toString()));
,那么你会得到您期望的值(即分区的结果为0.625,显示为62.5)
这是否是预期的行为或错误是有争议的 - 从规范中不清楚应该如何进行从Double到BigDecimal的强制。
我怎样才能得到正确的结果?
将最后一行更改为:
${ ( (strutsForm.currentUsage div 1024 div 1024) div (totalQuota.doubleValue()) ) * 100 }
应该避免Double到BigDecimal的问题强制。我无法确定它是否会起作用,因为我没有可以测试的环境,但似乎。