博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BigDecimal舍入模式使用及建议
阅读量:7116 次
发布时间:2019-06-28

本文共 4396 字,大约阅读时间需要 14 分钟。

1. 八种舍入模式

此节内容参考于 。

JDK1.5发布的枚举 RoundingMode 对 BigDecimal 的八种舍入模式进行了封装,用于取代 BigDecimal 中静态常量式的舍入模式:

public enum RoundingMode {    UP(BigDecimal.ROUND_UP),              // 0    DOWN(BigDecimal.ROUND_DOWN),          // 1    CEILING(BigDecimal.ROUND_CEILING),        // 2    FLOOR(BigDecimal.ROUND_FLOOR),           // 3    HALF_UP(BigDecimal.ROUND_HALF_UP),        // 4    HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),      // 5    HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),      // 6    UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);   // 7    final int oldMode;    private RoundingMode(int oldMode) {        this.oldMode = oldMode;    }    public static RoundingMode valueOf(int rm) {        switch(rm) {        case BigDecimal.ROUND_UP:            return UP;        case BigDecimal.ROUND_DOWN:            return DOWN;        case BigDecimal.ROUND_CEILING:            return CEILING;        case BigDecimal.ROUND_FLOOR:            return FLOOR;        case BigDecimal.ROUND_HALF_UP:            return HALF_UP;        case BigDecimal.ROUND_HALF_DOWN:            return HALF_DOWN;        case BigDecimal.ROUND_HALF_EVEN:            return HALF_EVEN;        case BigDecimal.ROUND_UNNECESSARY:            return UNNECESSARY;        default:            throw new IllegalArgumentException("argument out of range");        }    }}

1. UP

定义:远离零方向舍入。

解释:始终对非零舍弃部分前面的数字加 1。注意,此舍入模式始终不会减少计算值的绝对值。

2. DOWN

定义:向零方向舍入。

解释:从不对舍弃部分前面的数字加 1(即截尾)。注意,此舍入模式始终不会增加计算值的绝对值。

3. CEILING

定义:向正无限大方向舍入。

解释:如果结果为正,则舍入行为类似于 RoundingMode.UP;如果结果为负,则舍入行为类似于 RoundingMode.DOWN。注意,此舍入模式始终不会减少计算值。

4. FLOOR

定义:向负无限大方向舍入。

解释:如果结果为正,则舍入行为类似于 RoundingMode.DOWN;如果结果为负,则舍入行为类似于 RoundingMode.UP。注意,此舍入模式始终不会增加计算值。

5. HALF_UP

定义:向最接近的数字方向舍入,如果与两个相邻数字的距离相等,则向上舍入。

解释:如果被舍弃部分 >= 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN。注意,此舍入模式就是通常学校里讲的四舍五入。

6. HALF_DOWN

定义:向最接近的数字方向舍入,如果与两个相邻数字的距离相等,则向下舍入。

解释:如果被舍弃部分 > 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN。注意,此舍入模式就是通常讲的五舍六入。

7. HALF_EVEN

定义:向最接近数字方向舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。

解释:如果舍弃部分左边的数字为奇数,则舍入行为同 RoundingMode.HALF_UP;如果为偶数,则舍入行为同 RoundingMode.HALF_DOWN。注意,在重复进行一系列计算时,根据统计学,此舍入模式可以在统计上将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。此舍入模式类似于 Java 中对 float 和 double 算法使用的舍入策略。

8. UNNECESSARY

定义:用于断言请求的操作具有精确结果,因此不发生舍入。

解释:计算结果是精确的,不需要舍入,否则抛出 ArithmeticException。

官方示例:

根据给定的舍入模式将输入数字舍入为一位数的结果
输入数字 UP DOWN CEILING FLOOR HALF_UP HALF_DOWN HALF_EVEN UNNECESSARY
5.5 6 5 6 5 6 5 6 ArithmeticException
2.5 3 2 3 2 3 2 2 ArithmeticException
1.6 2 1 2 1 2 2 2 ArithmeticException
1.1 2 1 2 1 1 1 1 ArithmeticException
1.0 1 1 1 1 1 1 1 1
-1.0 -1 -1 -1 -1 -1 -1 -1 -1
-1.1 -2 -1 -1 -2 -1 -1 -1 ArithmeticException
-1.6 -2 -1 -1 -2 -2 -2 -2 ArithmeticException
-2.5 -3 -2 -2 -3 -3 -2 -2 ArithmeticException
-5.5 -6 -5 -5 -6 -6 -5 -6 ArithmeticException

2. 使用及建议

Java 官方API推荐使用新的 setScale(int newScale, RoundingMode roundingMode) 代替旧的 setScale(int newScale, int roundingMode)。

由于 BigDecimal 对象是不可变的(immutable),因此 setScale() 方法不会修改原来的 BigDecimal 对象值,这与 setX 的常规约定不同。相反,将会返回一个新的具有指定精度的 BigDecimal 对象,该对象不一定是新分配的,其非精度值由此 BigDecimal 的非精度值乘以或除以 10 的适当次幂来确定,以保持其整体值,如果精度值减少了,非精度值必须被除,并且该值可以更改,在这种情况下,将指定的舍入模式应用到除法中。

int decimal = 2;//保留小数位数double d1 = 0.525;double d2 = 0.625;double d3 = 0.425;double d4 = 0.325;System.out.println(BigDecimal.valueOf(d1).setScale(decimal, RoundingMode.HALF_EVEN) + " == " + new BigDecimal(d1).setScale(decimal, RoundingMode.HALF_EVEN));System.out.println(BigDecimal.valueOf(d2).setScale(decimal, RoundingMode.HALF_EVEN) + " == " + new BigDecimal(d2).setScale(decimal, RoundingMode.HALF_EVEN));System.out.println(BigDecimal.valueOf(d3).setScale(decimal, RoundingMode.HALF_EVEN) + " == " + new BigDecimal(d3).setScale(decimal, RoundingMode.HALF_EVEN));System.out.println(BigDecimal.valueOf(d4).setScale(decimal, RoundingMode.HALF_EVEN) + " == " + new BigDecimal(d4).setScale(decimal, RoundingMode.HALF_EVEN));/*  * output *  0.52 == 0.53 *  0.62 == 0.62 *  0.42 == 0.42 *  0.32 == 0.33 */

这里有一个问题new BigDecimal(double val),其结果有一定的不可预知性,导致结果不准确,应该使用 new BigDecimal(String val)new BigDecimal(Double.toString(val)),BigDecimal提供了一个静态的valueOf(double val) 方法快速完成这件事情。

System.out.println(new BigDecimal(0.525d));// output 0.52500000000000002220446049250313080847263336181640625System.out.println(new BigDecimal("0.525"));// output 0.525System.out.println(BigDecimal.valueOf(0.525));  // Double.toString(0.525) // output 0.525

 

转载于:https://www.cnblogs.com/mabaoqing/p/10244946.html

你可能感兴趣的文章
mac显示隐藏文件
查看>>
4-2 ADO.NET-查询和检索数据7
查看>>
组策略设置IE 11的Compatible View
查看>>
调研分享:Flipboard的使用特点和页面信息抽取机制
查看>>
TextMate Footnotes
查看>>
sizeof那道笔试题的秘密
查看>>
WCF简单教程(11) REST调用
查看>>
(Abstract Factory)抽象工厂模式的Java实现
查看>>
链表基础以及约瑟夫环的实现
查看>>
【iOS开发必备指南合集一】申请IDP/真机调试/GameCenter 指南/OpenFeint指南
查看>>
JavaScript的方法和技巧
查看>>
Android系统默认Home应用程序(Launcher)的启动过程源代码分析(4)
查看>>
Exchange Server2010系列之七:多邮箱搜索找出神秘邮件的幕后黑手
查看>>
《Pro ASP.NET MVC 3 Framework》学习笔记目录
查看>>
/dev/null Read-only file system 系统无法启动
查看>>
查询并导出、导入mysql中的存储过程
查看>>
VSeWSS更新文档
查看>>
WCF分布式开发步步为赢(8):使用数据集(DataSet)、数据表(DataTable)、集合(Collection)传递数据...
查看>>
Numpy:高维数组(矩阵)
查看>>
远程桌面不能复制粘贴解决办法
查看>>