BigDecimal分裂问题

时间:2014-12-04 10:43:49

标签: java jsp struts el bigdecimal

我的 struts表单中有两个字段:

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

jsp 上我使用将百分比显示为:

<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 为什么会这样?我怎么能得到正确的结果?

1 个答案:

答案 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的问题强制。我无法确定它是否会起作用,因为我没有可以测试的环境,但似乎。