【问题标题】:BigDecimal division issueBigDecimal除法问题
【发布时间】:2014-12-04 10:43:48
【问题描述】:

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

【问题讨论】:

  • 我认为,最简单的解决方案是在服务器端进行此计算并在视图页面上使用结果。
  • @SemihEker:你是对的。但我正在寻找是否也可以在 jsp 上完成。

标签: el java jsp struts el bigdecimal


【解决方案1】:

为什么会这样?

这是违反直觉的行为,但我认为这是用于除法的 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 的问题。我无法确定它是否会起作用,因为我没有可以测试的环境,但似乎可以。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 1970-01-01
    相关资源
    最近更新 更多