BigDecimal舍入模式使用及建议
1. 八种舍入模式
此节内容参考于 https://my.oschina.net/sunchp/blog/670909。
JDK1.5发布的枚举 RoundingMode 对 BigDecimal 的八种舍入模式进行了封装,用于取代 BigDecimal 中静态常量式的舍入模式:
public enum RoundingMode {
UP(BigDecimal.ROUND_UP),
DOWN(BigDecimal.ROUND_DOWN),
CEILING(BigDecimal.ROUND_CEILING),
FLOOR(BigDecimal.ROUND_FLOOR),
HALF_UP(BigDecimal.ROUND_HALF_UP),
HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
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.52500000000000002220446049250313080847263336181640625
System.out.println(new BigDecimal("0.525"));
// output 0.525
System.out.println(BigDecimal.valueOf(0.525)); // Double.toString(0.525)
// output 0.525
BigDecimal舍入模式使用及建议的更多相关文章
- BigDecimal 舍入模式(Rounding mode)介绍
BigDecimal 舍入模式(Rounding mode)介绍 什么样的经历,才能领悟成为架构师? >>> 1 RoundingMode介绍 package java.math ...
- BigDecimal的精度舍入模式详解
BigDecimal舍入模式介绍: 舍入模式在java.math.RoundingMode 里面: RoundingMode.CEILING :向正无限大方向舍入的舍入模式.如果结果为正,则舍入行为类 ...
- Java大数类BigDecimal及八种舍入模式的介绍
BigDecimal的引入 在利用Java编程语言开发银行.金融类等需要对数值进行高精度计算的软件时,我们经常使用BigDecimal和BigInteger这两个大数据类,而不是常见的int.long ...
- Java中BigDecimal的8种舍入模式
java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值和32位的整数标度(scale)组成. 如果为零或正数,则标度是小数点后的位 ...
- Java中BigDecimal的8种舍入模式是怎样的
Java中BigDecimal的8种舍入模式是怎样的?下面长沙欧柏泰克软件学院和大家一起来学习下吧: java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecima ...
- Java中BigDecimal的舍入模式
java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值和32位的整数标度(scale)组成. 如果为零或正数,则标度是小数点后的位 ...
- Java 舍入模式 数字的格式化
舍入模式: UP向远离0的方向舍入 始终对非零舍弃部分前面的数字加 1.此舍入模式始终不会减少计算值的绝对值. 例如:1.6 → 2 -1.6 → -2 1.1 → 2 ...
- Java BigDecimal 的舍入模式(RoundingMode)详解
BigDecimal.divide方法中必须设置roundingMode,不然会报错. ROUND_UP:向正无穷方向对齐(转换为正无穷方向最接近的所需数值) ROUND_DOWN:向负无穷方向对齐 ...
- 关于BigDecimal 和 double 类型保存金钱,以及精度问题,银行家舍入法
1. BigDecimal 类型数据 的创建,构造函数 有 public BigDecimal(BigInteger intVal, long val, int scale, int prec); p ...
随机推荐
- 使用timeit模块 测试两种方式生成列表的所用的时间
from timeit import Timer def test(): li=[] for i in range(10000): li.append(i) def test2(): li=[i fo ...
- 文件夹操作-DirectoryInfo类
DirectoryInfo类是一个密封类,它可以用来创建.移动.枚举目录和子目录.DirectoryInfo类包括4个属性,可以用来获取目录的名称.父目录等. DirectoryInfo类的属性表 属 ...
- Appium+python自动化18-brew、carthage和appium-doctor【转载】
前言 本篇安装brew.carthage,解决启动appium时的报错问题,另外安装appium-doctor检查appium的环境 1.brew 2.carthage 3.appium-doctor ...
- mysql的grant权限参数汇总
很明显总共28个权限:下面是具体的权限介绍:转载的,记录一下: 一.权限表 mysql数据库中的3个权限表:user .db. host 权限表的存取过程是: 1)先从user表中的host. use ...
- 关于python浮点数的精度问题。
若想严格按照四舍五入进行,可使用Decimal,代码如下: from decimal import Decimal, ROUND_HALF_UP def round(x, n): return Dec ...
- 武汉天喻的NFS 磁盘问题
public void AsyncPaper() { while (true) { try { var jsonText = RedisHelper.BlockPopItemFromList(&quo ...
- 【原创】SSIS-WMI 数据读取器任务:监控物理磁盘空间
1.背景 随着时间的推移,我们的DW会越来越大,也就意味着磁盘空间会越来越小,那如果哪一天留意不当,就会造成磁盘空间的不足而导致ETL失败,最终影响我们的系统的数据正确性和使用,更严重的有可能导致物理 ...
- Python的程序结构[3] -> 变量/Variable[1] -> LEGB 法则
LEGB法则 / LEGB Rule LEGB 变量搜索顺序 ---- 来源于<Python学习手册>/ Learning Python Page 419 ---- Python 的变量名 ...
- FZU-2216 The Longest Straight(尺取法)
Problem 2216 The Longest Straight Accept: 523 Submit: 1663Time Limit: 1000 mSec Memory Limit ...
- Android反编译调试源码
Android反编译调试源码 1. 反编译得到源码 直接在windows 命令行下输入命令java -jar apktool_2.0.0.jar d -d 小米运动_1.4.641_1058.apk ...