资讯专栏INFORMATION COLUMN

BigDecimal遇到的问题,大伙也说说

harriszh / 929人阅读

摘要:舍入方式需要弄明白自己的业务才用,别为了用而随便选一个用四舍五入模式从零四舍五入。原值结论都是向前进一位四舍五入到正无穷。

一:相除精度丢失的问题
  BigDecimal的api除法相对加减乘要实现的复杂多了,只介绍常用的我遇到的问题:

  问题:两数相除,如果9/3=3整除没问题,但是10/3=0.33333333......除不尽,这里不能让电脑一直除不尽,所以BigDecimal做出一些限制;

   必须按照(数,保留小数位(最好要合理限制最大精度),舍入方式)来操作

 

   否则就会抛出异常,例如:

public static void main(String[] args) {

    BigDecimal a = new BigDecimal(10);
    BigDecimal b = new BigDecimal(3);
    BigDecimal c = a.divide(b);
}

   执行:抛出

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1616)

二:舍入方式精度丢失的问题
  多数相乘时,请勿先进行四舍五入或者其他的方式,以最终计算结果为基础进行取舍精度,虽然一说就明白,但是这一个编码的习惯问题,特别是在金融行业。

  舍入方式需要弄明白自己的业务才用,别为了用而随便选一个用

  1.ROUND_UP:四舍五入模式从零四舍五入。

main(String[] args) {

    BigDecimal a =  BigDecimal(0.31);
    BigDecimal b =  BigDecimal(3);
    BigDecimal c = a.divide(b,1,BigDecimal.ROUND_UP);
    LOGGER.error("原值:0.1033333...///"+c.toString()+"=0.2");

    //结论:0-9都是向前进一位(且当0后还有小数位为前提)

}
  2.ROUND_DOWN 四舍五入模式到四舍五入接近零。

main(String[] args) {
     

    BigDecimal a =  BigDecimal(0.39);
    BigDecimal b =  BigDecimal(1);
    BigDecimal c = a.divide(b,1,BigDecimal.ROUND_DOWN);
    LOGGER.error("原值:0.39///"+c.toString()+"=0.3");

      //结论:1-9都是向前进一位

}

  3.ROUND_CEILING 四舍五入到正无穷。

public static void main(String[] args) {

    BigDecimal a = new BigDecimal(0.301);
    BigDecimal b = new BigDecimal(1);
    BigDecimal c = a.divide(b,1,BigDecimal.ROUND_CEILING);
    LOGGER.error("原值:0.301///"+c.toString()+"=0.4");

    //结论:与第一种类似,区别就是舍入到正无穷的范围大,当值为负数时舍入失效,当用第四种解决

}

  4.ROUND_FLOOR 四舍五入到负无穷

main(String[] args) {

    BigDecimal a =  BigDecimal(-0.301);
    BigDecimal b =  BigDecimal(1);
    BigDecimal c = a.divide(b,1,BigDecimal.ROUND_FLOOR);
    LOGGER.error("原值:0.301///"+c.toString()+"=0.4");

     //结论:与上面的正无穷舍入的方式相反,可以互补

}

  5.ROUND_HALF_UP 四舍五入方式四舍五入,除非两个邻边距离相等,则四舍五入。

public static void main(String[] args) {

    BigDecimal a = new BigDecimal(-0.36);
    BigDecimal b = new BigDecimal(1);
    BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_UP);
    LOGGER.error("原值:-0.36///"+c.toString()+"=-0.4");        //结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}

  6.ROUND_HALF_DOWN 四舍五入模式四舍五入,除非两个邻边距离相等

public static void main(String[] args) {

    BigDecimal a = new BigDecimal(-0.35);
    BigDecimal b = new BigDecimal(1);
    BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_DOWN );
    LOGGER.error("原值:-0.35///"+c.toString()+"=-0.3");        //结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}

  7.ROUND_HALF_EVEN 四舍五入的方式是四舍五入,除非两个邻边是等距的,在这种情况下,四舍五入对甚至邻居。

public static void main(String[] args) {

    BigDecimal a = new BigDecimal(-0.35);
    BigDecimal b = new BigDecimal(1);
    BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_EVEN );
    LOGGER.error("原值:-0.35///"+c.toString()+"=-0.3");        //结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}

  8.ROUND_UNNECESSARY 舍入模式,以断言所请求的操作具有精确值结果,因此不需要舍入。

public static void main(String[] args) {

    BigDecimal a = new BigDecimal(-0.36);
    BigDecimal b = new BigDecimal(1);
    BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_EVEN );
    LOGGER.error("原值:-0.36///"+c.toString()+"=-0.4");        //结论:正负数相同,以5为分界,<=5舍掉,>5的进1        // 断言中使用的,实际开发过程中最好不用
}

三:BigDecimal取值范围的 validation 校验问题总结
  常常在与客户端交互时需要做很多校验,在javax.validation下面有很多不错的校验规则

  

  @NotNull :不为空,适用任何地方(@NotBlank只是用字符类型)

  @DecimalMax:取得最大值范围

  @DecimalMin(value = "0.00", message = "") 取值最小值

三:BigDecimal精度科学计数法问题总结
  BigDecimal有一种方法是:stripTrailingZeros(),它提供了去掉小数点后面的多余的0,但是问题是:

  

public static void main(String[] args) {
    BigDecimal A = BigDecimal.valueOf(0.36000).stripTrailingZeros();
    BigDecimal B = new BigDecimal(0.36000).stripTrailingZeros();
    BigDecimal zeroDecimal = new BigDecimal(0.000).stripTrailingZeros();
    System.out.println("原值0.36000//////"+A.toPlainString()+"===0.36");
    System.out.println("原值0.36000//////"+B.toPlainString()+"===35999999999999998667732370449812151491641998291015625");
    System.out.println("原值0.00000//////"+zeroDecimal+"==0.0000////"+zeroDecimal.toPlainString()+"==0");
}

  ①:导出是excel会以科学计数法展示数据,如120 -》1.2+E2;

  ②:如果0.000然后用stripTrailingZeros()是无效的,导出时toPlainString()加上之后就可以了;

  ③:慎用new BigDecimal();源代码如下;

/**这个构造函数的结果可能有些不可预测。
*可能会假设编写{@code new BigDecimal(0.1)}

Java创建一个完全等于的{@code BigDecimal}

0.1(未缩放值为1,刻度为1),但它是

实际上等于 0.1000000000000000055511151231257827021181583404541015*625.
**/public BigDecimal(double val) {
this(val,MathContext.UNLIMITED);

}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73440.html

相关文章

  • 180706-BigDecimal除法精度问题

    摘要:除法的精度问题在使用的除法时,遇到一个鬼畜的问题,本以为的精度计算,结果使用返回,当然最终发现还是自己的使用姿势不对导致的,因此记录一下,避免后面重蹈覆辙问题抛出在使用做高精度的除法时,一不注意遇到了一个小问题,如下上面的输出是什么 showImg(https://segmentfault.com/img/remote/1460000015555232); BigDecimal除法的精...

    imccl 评论0 收藏0
  • 漫话:如何给女朋友解释什么是策略模式?

    摘要:策略策略,指的是可以实现目标的方案集合,在某些特定情况下,策略之间是可以相互替换的。如何计算金额我们先拿点外卖中会员折扣活动举例子来说明一下吧。这就是策略模式。策略模式提供了管理相关的算法族的办法。showImg(https://user-gold-cdn.xitu.io/2019/5/13/16aaf673fde1b546);周末无事,窝在家里面看《权力的游戏第八季》,看的很是津津有味,...

    fancyLuo 评论0 收藏0
  • 开发之路(设计模式三:装饰者模式)

    摘要:若要扩展功能,装饰者提供了比继承更有弹性的替代方案。装饰者模式意味着一群装饰者类,这些类用来包装具体组件。装饰者类反映出被装饰组件类型。装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。 嘿嘿嘿,你是不是很喜欢用继承呢?感觉没什么事情是一个爸爸类搞不定的,有的话就两个,快来跟我看看这个模式吧,它能让你断奶,给爱用继承的人一个全新的设计眼界。 直奔主题,你是否有听说...

    Vicky 评论0 收藏0
  • 第一个java后端项目总结

    摘要:项目环境用于发送请求测试项目介绍这是一个商城项目,本来想起名叫项目,发现自己并没有用。也是自己第一篇博客,记录一下自己的学习过程,希望一方面能多做写项目锻炼能力,另一方面也让自己在做完之后写写博客自己总结反思。 1.项目环境 IDEA15 spring4 mybatis3.4 mysql RestLet Client用于发送请求测试 2.项目介绍 这是一个商城项目,本来想起名叫SSM项...

    Hwg 评论0 收藏0
  • 支付系统设计实现(1)——支付与退款

    摘要:支付流程以上是微信支付的流程用户进入选择商品进行购买,在内部结算时生成用户本系统订单待支付状态,此时返回订单信息与支付方式列表用户确认金额无误,并选择支付方式。 支付流程 showImg(https://segmentfault.com/img/bVytNT?w=894&h=1042); 以上是微信app支付的流程: 用户进入app选择商品进行购买,在app内部结算时生成用户本系统订...

    zhigoo 评论0 收藏0

发表评论

0条评论

harriszh

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<