为什么会这样?
这是违反直觉的行为,但我认为这是用于除法的 EL 规范 (LInk to oracle EL spec) 的方式,即将变量强制转换为 BigDecimal。
代码的第一行:
${(strutsForm.totalQuota div 1024 div 1024 div 1024)}
会将 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));:Double 到 BigDecimal 的强制是使用 BigDecimal 构造函数完成的,该构造函数给出比例为 0 的 BigDecimal。如果使用 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 的问题。我无法确定它是否会起作用,因为我没有可以测试的环境,但似乎可以。