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舍入模式使用及建议的更多相关文章

  1. BigDecimal 舍入模式(Rounding mode)介绍

    BigDecimal 舍入模式(Rounding mode)介绍 什么样的经历,才能领悟成为架构师? >>>   1 RoundingMode介绍 package java.math ...

  2. BigDecimal的精度舍入模式详解

    BigDecimal舍入模式介绍: 舍入模式在java.math.RoundingMode 里面: RoundingMode.CEILING :向正无限大方向舍入的舍入模式.如果结果为正,则舍入行为类 ...

  3. Java大数类BigDecimal及八种舍入模式的介绍

    BigDecimal的引入 在利用Java编程语言开发银行.金融类等需要对数值进行高精度计算的软件时,我们经常使用BigDecimal和BigInteger这两个大数据类,而不是常见的int.long ...

  4. Java中BigDecimal的8种舍入模式

    java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值和32位的整数标度(scale)组成. 如果为零或正数,则标度是小数点后的位 ...

  5. Java中BigDecimal的8种舍入模式是怎样的

    Java中BigDecimal的8种舍入模式是怎样的?下面长沙欧柏泰克软件学院和大家一起来学习下吧:  java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecima ...

  6. Java中BigDecimal的舍入模式

    java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值和32位的整数标度(scale)组成. 如果为零或正数,则标度是小数点后的位 ...

  7. Java 舍入模式 数字的格式化

    舍入模式: UP向远离0的方向舍入 始终对非零舍弃部分前面的数字加 1.此舍入模式始终不会减少计算值的绝对值. 例如:1.6 → 2      -1.6 → -2      1.1 → 2      ...

  8. Java BigDecimal 的舍入模式(RoundingMode)详解

    BigDecimal.divide方法中必须设置roundingMode,不然会报错. ROUND_UP:向正无穷方向对齐(转换为正无穷方向最接近的所需数值) ROUND_DOWN:向负无穷方向对齐 ...

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

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

随机推荐

  1. Sqlite 约束条件 Constraints

    一.约束 Constraints 我们在数据库中存储数据的时候,有一些数据有明显的约束条件. 比如一所学校关于教师的数据表,其中的字段列可能有如下约束: 年龄 - 至少大于20岁.如果你想录入一个小于 ...

  2. java基础练习 13

    import java.util.Scanner; public class Thirtheen { /*输入某年某月某日,判断这一天是这一年的第几天?*/ public static void ma ...

  3. localhost、127.0.0.1和本机IP

    localhost 是个域名,不是地址,它可以被配置为任意的 IP 地址,不过通常情况下都指向 127.0.0.1(ipv4)和 [::1](ipv6) 整个127.* 网段通常被用作 loopbac ...

  4. JDK 8的依赖使用

    第一步:compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VER ...

  5. 2.tornado请求与响应

    之前我们介绍了tornado的基础流程,但还遗留了一些问题.今天我们就来解决遗留问题并学习新的内容 settings,使用tornado.web.Application(handler, **sett ...

  6. 学习SPRING BOOT, SPRING CLOUD之Eureka和security

    有意思,明天去杨浦报名了一个SPRING CLOUD沙龙, 今天再抓紧看看哈哈哈. Eureka服务端: EurekaApplication.java package com.packtpub.Eur ...

  7. AC日记——魔法少女LJJ bzoj 4399

    魔法少女LJJ 思路: 动态开点权值线段树+启发式合并: 来,上代码: #include <cmath> #include <cstdio> #include <cstr ...

  8. ubuntu 安装TensorFlow

    1.安装pip $ sudo apt-get install python-pip python-dev 2.安装 TensorFlow for Python 2.7 # Ubuntu/Linux - ...

  9. 第十四届华中科技大学程序设计竞赛 K Walking in the Forest【二分答案/最小化最大值】

    链接:https://www.nowcoder.com/acm/contest/106/K 来源:牛客网 题目描述 It's universally acknowledged that there'r ...

  10. 洛谷 P1506 拯救oibh总部【DFS/Flood Fill】

    题目背景 oibh总部突然被水淹没了!现在需要你的救援…… 题目描述 oibh被突来的洪水淹没了>.<还好oibh总部有在某些重要的地方起一些围墙,用号表示,而一个封闭的号区域洪水是进不去 ...