一:相除精度丢失的问题

  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);
    }

BigDecimal遇到的问题,大伙也说说的更多相关文章

  1. BigDecimal 详细解析

    参加工作之后发现公司项目的数据库有关数值的字段类型,很少是之前常用的float和double, 而是一个没有接触过的decimal,在Java中表示的类型为BigDecimal, 而在业务中常常有关B ...

  2. Java BigDecimal 转换,除法陷阱(转)

    源地址:   http://blog.csdn.net/niannian_315/article/details/24354251 今天在用BigDecimal“出现费解”现象,以前虽然知道要避免用, ...

  3. JAVA BigDecimal 小数点处理

    1,保留两位小数 方法一:{ double c=3.154215; java.text.DecimalFormat myformat=new java.text.DecimalFormat(" ...

  4. BigDecimal 处理集合

    1  创建一个BigDecimal 对象 BigDecimal Sum = new BigDecimal(0); 2  一个BigDecimal 对象,保留2位小数点 Sum.setScale(2,B ...

  5. BigDecimal用法详解

    一.简介Java在java.math包中提供的API类BigDecimal,用来对超过16位有效 位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更 ...

  6. 网站压力负载测试工具:Web版已逝,只好送大伙单机版

    前言: 最近老板资金周转出了点问题,工资好久没发了,于是暂闲置在家,静待老板弄到钱东山再起的消息: QQ群里,偶尔不时的会有人问,原来的分布式网站负载工具怎么下载不了啦?或者不能用啦?之类的问题. 我 ...

  7. java 大数据处理类 BigDecimal 解析

    这两天,由于我的必修课概率论里经常要用到排列组合的计算,感觉很麻烦,加上现代智能手机的计算器是没有这方面功能的. 所以,就自己动手写了个安卓的 排列组合 计算器,用了一天,发现有很大的问题,阶乘达百亿 ...

  8. BigDecimal 加减乘除

    BigDecimal bignum1 = new BigDecimal("10"); BigDecimal bignum2 = new BigDecimal("5&quo ...

  9. 关于BigDecimal 和 double 类型保存金钱,以及精度问题,银行家舍入法

    1. BigDecimal 类型数据 的创建,构造函数 有 public BigDecimal(BigInteger intVal, long val, int scale, int prec); p ...

随机推荐

  1. python 中numpy中函数hstack用法和作用

    定义: Stack arrays in sequence horizontally (column wise). Take a sequence of arrays and stack them ho ...

  2. (转)你真的会写单例模式吗——Java实现

    http://www.runoob.com/design-pattern/singleton-pattern.html 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模式, ...

  3. SQL Server性能优化(9)聚集索引的存储结构

    一.索引的概念和分类 索引的概念大家都知道,日常开发中我们也会使用常见的聚集索引.非聚集索引.但是除了这两者以外,sqlserver中还提供其他的索引,如: a. 唯一索引:不包含重复键的索引,聚集索 ...

  4. myslide 插件开发知识点总结和 css3 动画性能问题的研究

    myslide 插件开发知识点总结和 css3 动画性能问题的研究 这篇文章主要是总结最近开发过程中遇到的问题.有几个问题又是不容易发现原因的问题,但是最后的结果又是很简单的. 1.手机端的 slid ...

  5. 从零开始学 Web 之 jQuery(二)获取和操作元素的属性

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  6. android开发(3):列表listview的实现 | 下拉刷新

    APP里面的列表太常用了,系统提供的listview或grideview可以做到.另外,我希望这个列表能够下拉时触发刷新,于是考虑使用封装了这个功能的开源项目,这里介绍这个: https://gith ...

  7. input type=file实现图片上传,预览以及图片删除

    背景 前两天在做一个PC网站的意见反馈,其中涉及到了图片上传功能,要求可以上传多张图片,并且支持图片上传预览及图片删除, 图片上传这一块以前没怎么搞过,而且一般也很少会碰到这样的需求,所以在做这个功能 ...

  8. Filebeat+Kafka+Logstash+ElasticSearch+Kibana 日志采集方案

    前言 Elastic Stack 提供 Beats 和 Logstash 套件来采集任何来源.任何格式的数据.其实Beats 和 Logstash的功能差不多,都能够与 Elasticsearch 产 ...

  9. Tomcat 服务器安装 SSL证书,实现 HTTP 自动跳转 HTTPS

    本文以阿里云为例: 一.下载证书 1.1.登录阿里云:https://www.aliyun.com/ 1.2.控制台搜索:SSL证书 1.3.进入 SSL证书控制台 1.4.申请免费 SSL证书,已有 ...

  10. [JZOJ5987] 仙人掌毒题

    Description Solution 套路题... 全他娘的是套路... 首先如何处理仙人掌,可以在线拿 \(lct\) 维护,或者离线之后树剖.(\(lct\) 维护太毒了写不来,就离线树剖了又 ...