[BigDecimal精确度的计数保留法及精度丢失的解决办法]

BigDecimal精确度的计数保留法

在银行、帐户、计费等领域,BigDecimal提供了精确的数值计算。其中8种舍入方式值得掌握。

1、ROUND_UP

  • 舍入远离零的舍入模式。
  • 在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。
  • 注意,此舍入模式始终不会减少计算值的大小。
BigDecimal bd = new BigDecimal("2.18491");
//2.19
System.out.println(bd.setScale(2, BigDecimal.ROUND_UP));

2、ROUND_DOWN

  • 接近零的舍入模式。
  • 在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。
  • 注意,此舍入模式始终不会增加计算值的大小。
BigDecimal bd = new BigDecimal("2.18491");
//2.18
System.out.println(bd.setScale(2, BigDecimal.ROUND_DOWN));

3、ROUND_HALF_UP

  • 向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。
  • 如果舍弃部分 >= 0.5,则舍入行为与ROUND_UP相同;否则舍入行为与ROUND_DOWN相同。
  • 注意,这是我们大多数人在小学时就学过的舍入模式(四舍五入)。
BigDecimal bd = new BigDecimal("2.18491");
//2.18
System.out.println(bd.setScale(2, BigDecimal.ROUND_HALF_UP)); BigDecimal bd1 = new BigDecimal("2.18591");
//2.19
System.out.println(bd1.setScale(2, BigDecimal.ROUND_HALF_UP));

4、ROUND_HALF_DOWN

  • 向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向下舍入的舍入模式。
  • 如果舍弃部分 > 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。
BigDecimal bd = new BigDecimal("2.18500");
//2.18
System.out.println(bd.setScale(2, BigDecimal.ROUND_HALF_DOWN)); BigDecimal bd1 = new BigDecimal("2.18510");
//2.19
System.out.println(bd1.setScale(2, BigDecimal.ROUND_HALF_DOWN));

5、ROUND_HALF_DOWN 银行家舍入法

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。

如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;

如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。

注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。

此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。

如果前一位为奇数,则入位,否则舍去。

以下例子为保留小数点1位,那么这种舍入方式下的结果。

1.15>1.2
1.25>1.2

6、ROUND_CEILING

接近正无穷大的舍入模式。

如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;

如果为负,则舍入行为与 ROUND_DOWN 相同。

注意,此舍入模式始终不会减少计算值。

7、ROUND_FLOOR

接近负无穷大的舍入模式。

如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;

如果为负,则舍入行为与 ROUND_UP 相同。

注意,此舍入模式始终不会增加计算值。

8、ROUND_UNNECESSARY

断言请求的操作具有精确的结果,因此不需要舍入。

如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

BigDecimal精度丢失的问题

BigDecimal bdTest = new BigDecimal(1.745);
BigDecimal bdTest1 = new BigDecimal(0.745);
bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("bdTest:" + bdTest); // 1.75
System.out.println("bdTest1:" + bdTest1); // 0.74

运行以上代码可以看到,1.745四舍五入的结果是1.75,0.745四舍五入的结果是0.74。

原因

使用参数为float或double的BigDecimal创建对象会丢失精度。因此强烈建议不要使用参数为float或double的BigDecimal创建对象。

System.out.println(new BigDecimal(1.745)); // 1.74500000000000010658141036401502788066864013671875
System.out.println(new BigDecimal(0.745)); // 0.74499999999999999555910790149937383830547332763671875

解决方案

  1. 使用BigDecimal(String val)的构造方法创建对象
new BigDecimal("1.745");
  1. 使用使用BigDecimal的valueOf(double val)方法创建对象
BigDecimal.valueOf(1.745);

参考链接

  1. BigDecimal.ROUND_HALF_XXX的各种用法
  2. BigDecimal精度丢失

BigDecimal精度详解的更多相关文章

  1. BigDecimal 用法详解

    BigDecimal简介 BigDecimal用法: BigDecimal的构造方法 BigDecimal常用方法描述 BigDecimal比较 BigDecimal总结 BigDecimal简介 J ...

  2. BigDecimal用法详解(转)

    BigDecimal用法详解    http://www.cnblogs.com/linjiqin/p/3413894.html 一.简介Java在java.math包中提供的API类BigDecim ...

  3. BigDecimal用法详解

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

  4. Odoo小数精度及货币精度详解

    一.小数精度的设置 一般在设置-数据结构-精度设置中就可以对 小数类型的字段进行精度设置: 对于代码中定义为 digits=dp.get_precision('Product Price') 或 di ...

  5. Java之BigDecimal详解

    一.BigDecimal概述 ​ Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数,但在实 ...

  6. 【java提高】(19)---BigDecimal详解和精度问题

    BigDecimal详解和精度问题 一.背景 在实际开发中,对于 不需要任何准确计算精度的属性可以直接使用float或double,但是如果需要精确计算结果,则必须使用BigDecimal,例如价格. ...

  7. BigDecimal 使用方法详解

    BigDecimal 使用方法详解 博客分类: java基础 bigdecimalmultiplyadddivide  BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (sca ...

  8. Java BigDecimal详解,提供了丰富的四舍五入规则

    java.math.BigDecimal类提供用于算术,刻度操作,舍入,比较,哈希算法和格式转换操作. toString()方法提供BigDecimal的规范表示.它使用户可以完全控制舍入行为. 提供 ...

  9. BigDecimal的用法详解(保留两位小数,四舍五入,数字格式化,科学计数法转数字,数字里的逗号处理)

    转自:https://blog.csdn.net/ochangwen/article/details/51531866 一.简介 Java在java.math包中提供的API类BigDecimal,用 ...

随机推荐

  1. 简单创建一个SpringCloud2021.0.3项目(四)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上三篇教程 3. 日志处理 1. 创建日志公共模块 2. Eureka引入日志模块 4. 到此的功能代码 5. 注册中心换成naco ...

  2. git revert总结

    git revert git revert 是一种创建一次新的commit 来回退某次或某几次commit的一种方式 命令 // 创建一个新的commit,这个commit会删除(下面)commit- ...

  3. Ansible_基础模块

    特点:无主从,即装即用,基于ssh 安装ansible yum install epel-release -y yum install ansible -y 定义主机清单 vim /etc/ansib ...

  4. 将java的项目jar包打成镜像

    一.镜像.容器相关知识的概述 Docker 镜像 docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序.库.资源.配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷.环境变量 ...

  5. Elasticsearch API响应的一些常用选项

    我们可以点击Elasticsearch API以获取所需的响应,但是如果要修改API响应,以便我们更改显示格式或过滤掉某些字段,然后我们可以将这些选项与查询一起应用. 有一些常见的选项可以适用于API ...

  6. 使用 Auditbeat 模块监控 shell 命令

    使用 Auditbeat 模块监控 shell 命令 Auditbeat Audited 模块可以用来监控所有用户在系统上执行的 shell 命令.在终端用户偶尔才会登录的服务器上,通常需要进行监控. ...

  7. 延申三大问题中的第一个问题处理---原先shell脚本中启动jar文件命令的配置,附加参数等

    经过一系列的试错,最终采用的解决办法如下: 采用的配置文件 附加的启动参数 或者把这些都给统一添加到ConfigMap中

  8. 16. 综合使用tail、forward、copy和stdout

    通过一个例子进行阶段总结. 本示例使用到如下插件:in_tail, out_copy, out_stdout, out_forward, in_forward. 本示例包含两个节点: node_for ...

  9. Fluentd部署:错误排查

    介绍一下排查Fluentd运行时错误的几种方法. 查看日志 如果感觉Fluentd运行异常,请先查看日志.td-agent安装后,默认日志存放在/var/log/td-agent/td-agent.l ...

  10. Java实现6种常见排序

    1.冒泡排序(Bubble Sort) 第0轮 3 1 4 1 5 9 2 6 5 3 5 8 9 第1轮 1 3 1 4 5 2 6 5 3 5 8 9 9 第2轮 1 1 3 4 2 5 5 3 ...